Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions __tests__/interface.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ describe('Public Interface', () => {
'requestAndroidLocationPermissions',
'getAnnotationsLayerID',
'addCustomHeader',
'addCustomHeaderWithOptions',
'removeCustomHeader',

// animated
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,58 @@
package com.rnmapbox.rnmbx.modules

import com.mapbox.common.*

import com.rnmapbox.rnmbx.v11compat.httpinterceptor.*

data class CustomHttpHeadersOptions(val urlRegexp: Regex?)

data class CustomHttpHeadersMapValue(
val headerValue: String,
val options: CustomHttpHeadersOptions?
)

object CustomHttpHeaders : HttpServiceBase() {
const val LOG_TAG = "CustomHttpHeaders"

init {}

val map = mutableMapOf<String, String>()
val map = mutableMapOf<String, CustomHttpHeadersMapValue>()

fun addCustomHeader(headerName: String, headerValue: String) {
fun addCustomHeader(headerName: String, headerValue: String, options: CustomHttpHeadersOptions? = null) {
HttpServiceFactory.getInstance().setInterceptor(
this
)
map.put(headerName, headerValue)
map.put(headerName, CustomHttpHeadersMapValue(headerValue = headerValue, options = options))
}

fun removeCustomHeader(headerName: String) {
map.remove(headerName)
}

override fun onRequest(request: HttpRequest): HttpRequest {
fun getCustomRequestHeaders(customRequestHeaders: MutableMap<String, CustomHttpHeadersMapValue>, httpRequest: HttpRequest): HashMap<String, String> {
val headers = hashMapOf<String, String>()
for (entry in map.entries.iterator()) {
request.headers[entry.key] = entry.value
val urlRegexp = entry.value.options?.urlRegexp
if (urlRegexp != null) {
val destination = httpRequest.headers.getOrDefault("location", httpRequest.url)
if (urlRegexp.matches(destination)) {
headers[entry.key] = entry.value.headerValue
}
}
else {
headers[entry.key] = entry.value.headerValue
}
}
return headers
}

override fun onRequest(request: HttpRequest): HttpRequest {
request.headers.remove("Authorization")
request.headers.putAll(getCustomRequestHeaders(map, request))
return request
}

override fun onDownload(download: DownloadOptions): DownloadOptions {
for (entry in map.entries.iterator()) {
download.request.headers[entry.key] = entry.value
}
download.request.headers.putAll(getCustomRequestHeaders(map, download.request))
return download
}

Expand Down
16 changes: 15 additions & 1 deletion android/src/main/java/com/rnmapbox/rnmbx/modules/RNMBXModule.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.rnmapbox.rnmbx.modules

import android.os.Handler
import androidx.annotation.Nullable
import com.facebook.react.bridge.Promise
import com.mapbox.maps.extension.style.layers.properties.generated.LineJoin
import com.facebook.react.module.annotations.ReactModule
Expand All @@ -11,6 +12,8 @@ import com.rnmapbox.rnmbx.events.constants.EventTypes
import com.rnmapbox.rnmbx.modules.RNMBXOfflineModule
import com.rnmapbox.rnmbx.modules.RNMBXLocationModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.buildReadableMap
import com.facebook.react.common.MapBuilder
import com.mapbox.bindgen.None
import com.mapbox.common.*
Expand All @@ -24,6 +27,7 @@ import java.util.HashMap

import com.rnmapbox.rnmbx.v11compat.resourceoption.*
import com.rnmapbox.rnmbx.v11compat.mapboxmap.*
import java.util.regex.PatternSyntaxException

@ReactModule(name = RNMBXModule.REACT_CLASS)
class RNMBXModule(private val mReactContext: ReactApplicationContext) : ReactContextBaseJavaModule(
Expand Down Expand Up @@ -165,7 +169,17 @@ class RNMBXModule(private val mReactContext: ReactApplicationContext) : ReactCon

@ReactMethod
fun addCustomHeader(headerName: String, headerValue: String) {
CustomHttpHeaders.addCustomHeader(headerName, headerValue)
addCustomHeaderWithOptions(headerName, headerValue)
}

@ReactMethod
fun addCustomHeaderWithOptions(headerName: String, headerValue: String, options: ReadableMap? = buildReadableMap { }) {
try {
val urlRegexp = options?.getString("urlRegexp")?.toRegex()
CustomHttpHeaders.addCustomHeader(headerName, headerValue, CustomHttpHeadersOptions(urlRegexp = urlRegexp))
} catch (e: PatternSyntaxException) {
Logger.e(CustomHttpHeaders.LOG_TAG, e.localizedMessage ?: "Error converting ${options?.getString("urlRegexp")} to regex")
}
}

@ReactMethod
Expand Down
6 changes: 6 additions & 0 deletions docs/CustomHttpHeaders.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ You can add and remove headers at runtime.
MapboxGL.removeCustomHeader('Authorization');
```

### To add a header based on url

```javascript
MapboxGL.addCustomHeaderWithOptions('Authorization', '{auth header}', { urlRegexp: '^https:\/\/api\.mapbox\.com\/(.*)$' });
```

### Working example

```tsx
Expand Down
9 changes: 9 additions & 0 deletions docs/Mapbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ gets the accessToken
| `headerName` | `String` | `Yes` | name for customHeader |
| `headerValue` | `String` | `Yes` | value for customHeader |

### addCustomHeaderWithOptions(headerName, headerValue, options)

#### arguments
| Name | Type | Required | Description |
| ---- | :--: | :------: | :----------: |
| `headerName` | `String` | `Yes` | name for customHeader |
| `headerValue` | `String` | `Yes` | value for customHeader |
| `options` | `{ urlRegexp }` | `No` | optional configurations for customHeader |

#### Description
also see [CustomHttpHeaders](/docs/CustomHttpHeaders.md)

Expand Down
8 changes: 8 additions & 0 deletions example/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
},
});

Mapbox.addCustomHeader('Custom-Header', 'global-header-value');
Mapbox.addCustomHeaderWithOptions('Mapbox-Api-Header-Value', 'api-header-value', {

Check warning on line 29 in example/src/App.js

View workflow job for this annotation

GitHub Actions / lint_test_generate

Replace `'Mapbox-Api-Header-Value',·'api-header-value',` with `⏎··'Mapbox-Api-Header-Value',⏎··'api-header-value',⏎·`
urlRegexp: '^https:\/\/api\.mapbox\.com\/(.*)$',

Check warning on line 30 in example/src/App.js

View workflow job for this annotation

GitHub Actions / lint_test_generate

Unnecessary escape character: \/

Check warning on line 30 in example/src/App.js

View workflow job for this annotation

GitHub Actions / lint_test_generate

Unnecessary escape character: \.

Check warning on line 30 in example/src/App.js

View workflow job for this annotation

GitHub Actions / lint_test_generate

Unnecessary escape character: \.

Check warning on line 30 in example/src/App.js

View workflow job for this annotation

GitHub Actions / lint_test_generate

Unnecessary escape character: \/

Check warning on line 30 in example/src/App.js

View workflow job for this annotation

GitHub Actions / lint_test_generate

Unnecessary escape character: \/

Check warning on line 30 in example/src/App.js

View workflow job for this annotation

GitHub Actions / lint_test_generate

Insert `··`
});

Check warning on line 31 in example/src/App.js

View workflow job for this annotation

GitHub Actions / lint_test_generate

Replace `}` with `··},⏎`
// This header will not be added to requests to api.mapbox.com
Mapbox.addCustomHeaderWithOptions('Other-Api-Header-Value', 'other-api-header-value', {

Check warning on line 33 in example/src/App.js

View workflow job for this annotation

GitHub Actions / lint_test_generate

Replace `'Other-Api-Header-Value',·'other-api-header-value',` with `⏎··'Other-Api-Header-Value',⏎··'other-api-header-value',⏎·`
urlRegexp: '^https:\/\/api\.other\.com\/(.*)$',

Check warning on line 34 in example/src/App.js

View workflow job for this annotation

GitHub Actions / lint_test_generate

Insert `··`
});
Mapbox.setAccessToken(config.get('accessToken'));

console.log('### App.js - Mapbox:', Mapbox);
Expand Down
43 changes: 36 additions & 7 deletions ios/RNMBX/CustomHttpHeaders.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import MapboxMaps

struct CustomHttpHeadersOptions {
var urlRegexp: NSRegularExpression?
}

struct CustomHttpHeadersMapValue {
var headerValue: String
var options: CustomHttpHeadersOptions
}

class CustomHttpHeaders : HttpServiceInterceptorInterface {
#if RNMBX_11
func onRequest(for request: HttpRequest, continuation: @escaping HttpServiceInterceptorRequestContinuation) {
Expand All @@ -18,7 +27,7 @@ class CustomHttpHeaders : HttpServiceInterceptorInterface {
return headers
}()

var customHeaders : [String:String] = [:]
var customHeaders : [String:CustomHttpHeadersMapValue] = [:]

func install() {
#if RNMBX_11
Expand All @@ -38,19 +47,39 @@ class CustomHttpHeaders : HttpServiceInterceptorInterface {
}

// MARK: - HttpServiceInterceptorInterface

func getCustomRequestHeaders(for request: HttpRequest, with customHeaders: [String: CustomHttpHeadersMapValue]) -> [String: String] {
var headers: [String: String] = [:]
let urlString = request.url

func onRequest(for request: HttpRequest) -> HttpRequest {
customHeaders.forEach {(key, value) in
request.headers[key] = value
for (key, entry) in customHeaders {
let options = entry.options

if let pattern = options.urlRegexp {
do {
let range = NSRange(location: 0, length: urlString.utf16.count)
if pattern.firstMatch(in: urlString, options: [], range: range) != nil {
headers[key] = entry.headerValue
}
}
} else {
headers[key] = entry.headerValue
}
}
return headers
}


func onRequest(for request: HttpRequest) -> HttpRequest {
let customHeaders = getCustomRequestHeaders(for: request, with: customHeaders)
request.headers.merge(customHeaders) { (_, new) in new }
return request
}

#if !RNMBX_11
func onDownload(forDownload download: DownloadOptions) -> DownloadOptions {
customHeaders.forEach {(key,value) in
download.request.headers[key] = value
}
let customHeaders = getCustomRequestHeaders(for: download.request, with: customHeaders)
download.request.headers.merge(customHeaders) { (_, new) in new }
return download
}
#endif
Expand Down
1 change: 1 addition & 0 deletions ios/RNMBX/RNMBXModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ @interface RCT_EXTERN_MODULE(RNMBXModule, NSObject)
RCT_EXTERN_METHOD(setAccessToken:(NSString *)accessToken resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(addCustomHeader:(NSString *)headerName forHeaderValue:(NSString *) headerValue)
RCT_EXTERN_METHOD(addCustomHeaderWithOptions:(NSString *)headerName forHeaderValue:(NSString *) headerValue forOptions:(nullable NSDictionary *) options)
RCT_EXTERN_METHOD(removeCustomHeader:(NSString *)headerName)

RCT_EXTERN_METHOD(setTelemetryEnabled:(BOOL)telemetryEnabled)
Expand Down
18 changes: 16 additions & 2 deletions ios/RNMBX/RNMBXModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,23 @@ class RNMBXModule : NSObject {
RNMBXModule.accessToken = token
resolver(token)
}

@objc func addCustomHeader(_ headerName: String, forHeaderValue headerValue: String) {
addCustomHeaderWithOptions(headerName, forHeaderValue: headerValue, forOptions: nil)
}

@objc func addCustomHeader(_ headerName: String, forHeaderValue headerValue: String ) {
CustomHttpHeaders.shared.customHeaders[headerName] = headerValue
@objc func addCustomHeaderWithOptions(_ headerName: String, forHeaderValue headerValue: String, forOptions options: NSDictionary?) {
var urlRegexp: NSRegularExpression? = nil
if let pattern = options?.value(forKey: "urlRegexp") as? String {
do {
urlRegexp = try NSRegularExpression(pattern: pattern)
}
catch {
Logger.log(level: .error, message: "Invalid regex pattern: \(error.localizedDescription)")
}
}

CustomHttpHeaders.shared.customHeaders[headerName] = CustomHttpHeadersMapValue(headerValue: headerValue, options: CustomHttpHeadersOptions(urlRegexp: urlRegexp))
}

@objc func removeCustomHeader(_ headerName: String) {
Expand Down
12 changes: 10 additions & 2 deletions src/RNMBXModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,16 @@ interface RNMBXModule {
TileServers: {
Mapbox: string;
};

removeCustomHeader(headerName: string): void;
addCustomHeader(headerName: string, headerValue: string): void;
addCustomHeader(
headerName: string,
headerValue: string
): void;
addCustomHeaderWithOptions(
headerName: string,
headerValue: string,
options: { urlRegexp?: string },
): void;
setAccessToken(accessToken: string | null): Promise<string | null>;
setWellKnownTileServer(tileServer: string): void;
clearData(): Promise<void>;
Expand Down Expand Up @@ -59,6 +66,7 @@ export const {
TileServers,
removeCustomHeader,
addCustomHeader,
addCustomHeaderWithOptions,
setAccessToken,
setWellKnownTileServer,
clearData,
Expand Down
Loading