Skip to content

Commit 5d5242d

Browse files
authored
Merge pull request #217 from omeratt/feature/support_external_interceptors
feat: Adding custom debug interceptor support
2 parents fd39ff1 + 7e1daf3 commit 5d5242d

File tree

3 files changed

+140
-3
lines changed

3 files changed

+140
-3
lines changed

README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,81 @@ getCookies('domain')
190190
})
191191

192192
```
193+
194+
## Debug Interceptors & Request/Response Observers
195+
196+
This library now supports custom debug interceptors and request/response observers to help with debugging network requests in development builds. These features are only active in DEBUG builds for security reasons.
197+
198+
### Summary of Recent Enhancements
199+
200+
**Latest Updates (June 2025):**
201+
1. **Android Custom Debug Interceptor Support** - Added ability to inject custom OkHttp interceptors for debugging network traffic
202+
2. **Android Debug Interceptor Refactoring** - Improved code organization by extracting interceptor logic into a dedicated method
203+
3. **iOS Request/Response Observers** - Added observer methods to monitor network requests and responses on iOS for debugging purposes
204+
205+
### Android Debug Interceptor
206+
207+
Add custom debug interceptors to monitor and modify HTTP requests/responses in Android:
208+
209+
```java
210+
// In your Android application code (Java/Kotlin)
211+
import com.toyberman.Utils.OkHttpUtils;
212+
import okhttp3.Interceptor;
213+
import okhttp3.logging.HttpLoggingInterceptor;
214+
215+
// Example: Add a custom logging interceptor
216+
Interceptor customInterceptor = new HttpLoggingInterceptor()
217+
.setLevel(HttpLoggingInterceptor.Level.BODY);
218+
219+
// Add the interceptor (only works in DEBUG builds)
220+
OkHttpUtils.addInterceptorForDebug(customInterceptor);
221+
```
222+
223+
**Features:**
224+
- Only active in DEBUG builds for security
225+
- Supports any OkHttp interceptor
226+
- Useful for detailed request/response logging
227+
- Can be used for request modification during development
228+
229+
### iOS Request/Response Observers
230+
231+
Monitor network requests and responses on iOS using observer methods:
232+
233+
```objc
234+
// In your iOS application code (Objective-C)
235+
#import "RNSslPinning.h"
236+
237+
// Set request observer to monitor outgoing requests
238+
[RNSslPinning setRequestObserver:^(NSURLRequest *request) {
239+
NSLog(@"Request: %@ %@", request.HTTPMethod, request.URL);
240+
// Add your custom request monitoring logic here
241+
}];
242+
243+
// Set response observer to monitor responses with timing
244+
[RNSslPinning setResponseObserver:^(NSURLRequest *request, NSHTTPURLResponse *response, NSData *data, NSTimeInterval startTime) {
245+
NSTimeInterval duration = ([[NSDate date] timeIntervalSince1970] * 1000.0) - startTime;
246+
NSLog(@"Response: %ld for %@ (%.2fms)", (long)response.statusCode, request.URL, duration);
247+
// Add your custom response monitoring logic here
248+
}];
249+
```
250+
251+
**Features:**
252+
- Only active in DEBUG builds for security
253+
- Monitor all outgoing requests
254+
- Track response data, status codes, and timing
255+
- Handle both successful responses and error cases
256+
- Captures original request details for correlation
257+
258+
### Use Cases
259+
260+
- **Network Debugging**: Monitor request/response flow during development
261+
- **Performance Analysis**: Track request timing and response sizes
262+
- **SSL/TLS Troubleshooting**: Debug certificate pinning issues
263+
- **API Development**: Verify request formats and response handling
264+
- **Integration Testing**: Monitor network calls during automated tests
265+
266+
**Note**: These debugging features are automatically disabled in production builds for security and performance reasons.
267+
193268
## Multipart request (FormData)
194269
195270
```javascript

android/src/main/java/com/toyberman/Utils/OkHttpUtils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
import okhttp3.CertificatePinner;
3333
import okhttp3.CookieJar;
34+
import okhttp3.Interceptor;
3435
import okhttp3.MediaType;
3536
import okhttp3.MultipartBody;
3637
import okhttp3.OkHttpClient;
@@ -54,6 +55,14 @@ public class OkHttpUtils {
5455
private static SSLContext sslContext;
5556
private static String content_type = "application/json; charset=utf-8";
5657
public static MediaType mediaType = MediaType.parse(content_type);
58+
private static Interceptor customDebugInterceptor = null;
59+
60+
// This method is used to add a custom debug interceptor if it exists and the build is in debug mode.
61+
private static void addCustomDebugInterceptor(OkHttpClient.Builder clientBuilder) {
62+
if (BuildConfig.DEBUG && customDebugInterceptor != null) {
63+
clientBuilder.addInterceptor(customDebugInterceptor);
64+
}
65+
}
5766

5867
public static OkHttpClient buildOkHttpClient(CookieJar cookieJar, String domainName, ReadableArray certs, ReadableMap options) {
5968

@@ -82,6 +91,7 @@ public static OkHttpClient buildOkHttpClient(CookieJar cookieJar, String domainN
8291
if (BuildConfig.DEBUG) {
8392
clientBuilder.addInterceptor(logging);
8493
}
94+
addCustomDebugInterceptor(clientBuilder);
8595

8696
client = clientBuilder
8797
.build();
@@ -123,6 +133,7 @@ public static OkHttpClient buildDefaultOHttpClient(CookieJar cookieJar, String d
123133
if (BuildConfig.DEBUG) {
124134
clientBuilder.addInterceptor(logging);
125135
}
136+
addCustomDebugInterceptor(clientBuilder);
126137

127138
defaultClient = clientBuilder.build();
128139
}
@@ -316,4 +327,10 @@ private static void setRequestHeaders(ReadableMap options, Request.Builder reque
316327
mediaType = MediaType.parse(content_type);
317328
}
318329
}
330+
331+
public static void addInterceptorForDebug(Interceptor interceptor) {
332+
if (BuildConfig.DEBUG) {
333+
customDebugInterceptor = interceptor;
334+
}
335+
}
319336
}

ios/RNSslPinning/RNSslPinning.m

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
#import "RNSslPinning.h"
55
#import "AFNetworking.h"
66

7+
static void (^_requestObserver)(NSURLRequest *) = nil;
8+
static void (^_responseObserver)(NSURLRequest *, NSHTTPURLResponse *, NSData *, NSTimeInterval) = nil;
9+
710
@interface RNSslPinning()
811

912
@property (nonatomic, strong) NSURLSessionConfiguration *sessionConfig;
@@ -13,6 +16,18 @@ @interface RNSslPinning()
1316
@implementation RNSslPinning
1417
RCT_EXPORT_MODULE();
1518

19+
+ (void)setRequestObserver:(void (^)(NSURLRequest *))observer {
20+
#if DEBUG
21+
_requestObserver = [observer copy];
22+
#endif
23+
}
24+
25+
+ (void)setResponseObserver:(void (^)(NSURLRequest *, NSHTTPURLResponse *, NSData *, NSTimeInterval))observer {
26+
#if DEBUG
27+
_responseObserver = [observer copy];
28+
#endif
29+
}
30+
1631
- (instancetype)init
1732
{
1833
self = [super init];
@@ -65,14 +80,44 @@ - (instancetype)init
6580

6681

6782
-(void)performRequest:(AFURLSessionManager*)manager obj:(NSDictionary *)obj request:(NSMutableURLRequest*) request callback:(RCTResponseSenderBlock) callback {
68-
83+
#if DEBUG
84+
if (_requestObserver) {
85+
_requestObserver(request);
86+
}
87+
#endif
88+
89+
NSURLRequest *capturedRequest = [request copy]; // 🧠 Save the original request - for interceptors purposes
90+
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970] * 1000.0;
91+
92+
6993
[[manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
70-
71-
7294
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
7395
NSString *bodyString = [[NSString alloc] initWithData: responseObject encoding:NSUTF8StringEncoding];
7496
NSInteger statusCode = httpResp.statusCode;
7597

98+
// Don't create a synthetic response - pass the real one to observer along with error
99+
if (error && (!httpResp || httpResp.statusCode == 0)) {
100+
bodyString = error.localizedDescription;
101+
}
102+
103+
#if DEBUG
104+
if (_responseObserver) {
105+
NSData *rawData = nil;
106+
if (responseObject) {
107+
rawData = [responseObject isKindOfClass:[NSData class]]
108+
? responseObject
109+
: [NSJSONSerialization dataWithJSONObject:responseObject options:0 error:nil];
110+
} else if (error) {
111+
// Create error response data if we have an error but no response data
112+
NSString *errorMessage = error.localizedDescription ?: @"Unknown error";
113+
rawData = [errorMessage dataUsingEncoding:NSUTF8StringEncoding];
114+
}
115+
116+
// Pass the raw error to our observer with the start time
117+
_responseObserver(capturedRequest, httpResp, rawData ?: [NSData new], startTime);
118+
}
119+
#endif
120+
76121
if (!error) {
77122
// if(obj[@"responseType"]){
78123
NSString * responseType = obj[@"responseType"];

0 commit comments

Comments
 (0)