react-native-windows 0.68.1 → 0.69.0-preview.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.flowconfig +1 -3
- package/Chakra/ChakraHelpers.cpp +0 -1
- package/Directory.Build.props +3 -0
- package/Directory.Build.targets +1 -1
- package/Folly/TEMP_UntilFollyUpdate/dynamic-inl.h +1411 -0
- package/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.cpp +336 -0
- package/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.h +182 -0
- package/Libraries/ActionSheetIOS/ActionSheetIOS.js +7 -0
- package/Libraries/ActionSheetIOS/NativeActionSheetManager.js +1 -0
- package/Libraries/Alert/Alert.windows.js +2 -2
- package/Libraries/Animated/AnimatedImplementation.js +1 -1
- package/Libraries/Animated/NativeAnimatedHelper.js +55 -9
- package/Libraries/Animated/NativeAnimatedModule.js +1 -0
- package/Libraries/Animated/NativeAnimatedTurboModule.js +1 -0
- package/Libraries/Animated/animations/TimingAnimation.js +6 -11
- package/Libraries/Animated/createAnimatedComponent.js +2 -2
- package/Libraries/Animated/nodes/AnimatedColor.js +95 -29
- package/Libraries/Animated/nodes/AnimatedInterpolation.js +19 -22
- package/Libraries/Animated/nodes/AnimatedNode.js +2 -2
- package/Libraries/Animated/nodes/AnimatedValue.js +1 -1
- package/Libraries/AppState/AppState.js +1 -1
- package/Libraries/Blob/URL.js +7 -1
- package/Libraries/Components/Button.js +3 -0
- package/Libraries/Components/Button.windows.js +4 -0
- package/Libraries/Components/DatePickerAndroid/NativeDatePickerAndroid.js +5 -0
- package/Libraries/Components/Pressable/Pressable.js +3 -3
- package/Libraries/Components/Pressable/Pressable.windows.js +3 -3
- package/Libraries/Components/ScrollView/AndroidHorizontalScrollViewNativeComponent.js +47 -38
- package/Libraries/Components/ScrollView/ScrollContentViewNativeComponent.js +15 -7
- package/Libraries/Components/ScrollView/ScrollView.js +1 -1
- package/Libraries/Components/ScrollView/ScrollViewNativeComponent.js +16 -3
- package/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +3 -1
- package/Libraries/Components/Slider/Slider.js +0 -2
- package/Libraries/Components/Slider/SliderNativeComponent.js +0 -1
- package/Libraries/Components/StatusBar/StatusBar.js +6 -1
- package/Libraries/Components/Switch/Switch.js +11 -1
- package/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +114 -109
- package/Libraries/Components/TextInput/RCTMultilineTextInputNativeComponent.js +17 -9
- package/Libraries/Components/TextInput/RCTSingelineTextInputNativeComponent.js +13 -5
- package/Libraries/Components/TextInput/RCTTextInputViewConfig.js +10 -0
- package/Libraries/Components/TextInput/TextInput.js +1 -8
- package/Libraries/Components/TextInput/TextInput.windows.js +4 -9
- package/Libraries/Components/TextInput/TextInputState.js +10 -2
- package/Libraries/Components/TextInput/TextInputState.windows.js +10 -3
- package/Libraries/Components/TextInput/WindowsTextInputNativeComponent.js +1 -1
- package/Libraries/Components/Touchable/TouchableBounce.js +1 -0
- package/Libraries/Components/Touchable/TouchableHighlight.js +1 -0
- package/Libraries/Components/Touchable/TouchableHighlight.windows.js +6 -5
- package/Libraries/Components/Touchable/TouchableNativeFeedback.js +1 -0
- package/Libraries/Components/Touchable/TouchableOpacity.js +7 -1
- package/Libraries/Components/Touchable/TouchableOpacity.windows.js +11 -5
- package/Libraries/Components/Touchable/TouchableWithoutFeedback.js +2 -0
- package/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js +2 -0
- package/Libraries/Components/View/ReactNativeViewAttributes.js +1 -0
- package/Libraries/Components/View/ReactNativeViewAttributes.windows.js +1 -0
- package/Libraries/Components/View/View.windows.js +33 -1
- package/Libraries/Components/View/ViewNativeComponent.js +68 -8
- package/Libraries/Components/View/ViewPropTypes.js +36 -4
- package/Libraries/Components/View/ViewPropTypes.windows.js +36 -4
- package/Libraries/Core/Devtools/parseHermesStack.js +1 -1
- package/Libraries/Core/ExceptionsManager.js +1 -1
- package/Libraries/Core/RawEventEmitter.js +38 -0
- package/Libraries/Core/ReactNativeVersion.js +2 -2
- package/Libraries/Core/polyfillPromise.js +32 -0
- package/Libraries/Core/setUpReactDevTools.js +3 -2
- package/Libraries/EventEmitter/NativeEventEmitter.js +3 -3
- package/Libraries/EventEmitter/RCTDeviceEventEmitter.js +2 -1
- package/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js +3 -3
- package/Libraries/Events/CustomEvent.js +32 -0
- package/Libraries/Events/EventPolyfill.js +239 -0
- package/Libraries/Image/Image.android.js +0 -6
- package/Libraries/Image/Image.ios.js +0 -6
- package/Libraries/Image/Image.windows.js +2 -8
- package/Libraries/Image/ImageViewNativeComponent.js +18 -3
- package/Libraries/Image/TextInlineImageNativeComponent.js +23 -15
- package/Libraries/Inspector/Inspector.js +2 -4
- package/Libraries/Interaction/BridgeSpyStallHandler.js +4 -3
- package/Libraries/Interaction/InteractionManager.js +1 -12
- package/Libraries/Interaction/TaskQueue.js +5 -4
- package/Libraries/LayoutAnimation/LayoutAnimation.js +13 -0
- package/Libraries/Linking/Linking.js +1 -1
- package/Libraries/Lists/FlatList.js +27 -6
- package/Libraries/Lists/VirtualizedList.js +71 -55
- package/Libraries/Lists/VirtualizedListContext.js +7 -3
- package/Libraries/Lists/VirtualizedSectionList.js +2 -2
- package/Libraries/Lists/__tests__/{FillRateHelper-test.windows.js → FillRateHelper-test.js} +2 -2
- package/Libraries/Lists/__tests__/{FlatList-test.windows.js → FlatList-test.js} +2 -2
- package/Libraries/Lists/__tests__/{SectionList-test.windows.js → SectionList-test.js} +14 -14
- package/Libraries/Lists/__tests__/{VirtualizeUtils-test.windows.js → VirtualizeUtils-test.js} +3 -3
- package/Libraries/Lists/__tests__/{VirtualizedList-test.windows.js → VirtualizedList-test.js} +91 -42
- package/Libraries/Lists/__tests__/{VirtualizedSectionList-test.windows.js → VirtualizedSectionList-test.js} +13 -13
- package/Libraries/LogBox/Data/LogBoxData.js +2 -2
- package/Libraries/LogBox/Data/LogBoxLog.js +1 -1
- package/Libraries/LogBox/Data/LogBoxSymbolication.js +1 -1
- package/Libraries/LogBox/Data/parseLogBoxLog.js +1 -1
- package/Libraries/LogBox/LogBox.js +2 -21
- package/Libraries/LogBox/UI/LogBoxInspectorFooter.js +1 -0
- package/Libraries/LogBox/UI/LogBoxInspectorHeader.js +2 -1
- package/Libraries/NativeComponent/BaseViewConfig.android.js +295 -0
- package/Libraries/NativeComponent/BaseViewConfig.ios.js +333 -0
- package/Libraries/NativeComponent/BaseViewConfig.windows.js +334 -0
- package/Libraries/NativeComponent/NativeComponentRegistry.js +0 -2
- package/Libraries/NativeComponent/PlatformBaseViewConfig.js +24 -0
- package/Libraries/NativeComponent/StaticViewConfigValidator.js +7 -42
- package/Libraries/NativeComponent/ViewConfig.js +4 -4
- package/Libraries/NativeComponent/ViewConfigIgnore.js +54 -0
- package/Libraries/Network/FormData.js +7 -1
- package/Libraries/Pressability/Pressability.js +115 -46
- package/Libraries/Pressability/Pressability.windows.js +190 -74
- package/Libraries/Pressability/PressabilityDebug.js +5 -9
- package/Libraries/PushNotificationIOS/NativePushNotificationManagerIOS.js +1 -0
- package/Libraries/ReactNative/AppContainer.js +1 -1
- package/Libraries/ReactNative/{DummyUIManager.js → BridgelessUIManager.js} +62 -40
- package/Libraries/ReactNative/PaperUIManager.windows.js +5 -5
- package/Libraries/ReactNative/ReactNativeFeatureFlags.js +39 -0
- package/Libraries/ReactNative/UIManager.js +2 -3
- package/Libraries/ReactNative/renderApplication.js +4 -0
- package/Libraries/ReactPrivate/ReactNativePrivateInterface.js +8 -0
- package/Libraries/Renderer/implementations/ReactFabric-dev.js +5908 -4906
- package/Libraries/Renderer/implementations/ReactFabric-prod.js +2100 -1918
- package/Libraries/Renderer/implementations/ReactFabric-profiling.js +2567 -2352
- package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +5610 -4844
- package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js +1710 -1556
- package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.js +1830 -1639
- package/Libraries/Renderer/shims/ReactNativeTypes.js +2 -1
- package/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +2 -1
- package/Libraries/StyleSheet/EdgeInsetsPropType.js +4 -1
- package/Libraries/StyleSheet/StyleSheetTypes.js +59 -66
- package/Libraries/StyleSheet/normalizeColor.js +1 -1
- package/Libraries/StyleSheet/private/_StyleSheetTypesOverrides.js +15 -0
- package/Libraries/StyleSheet/private/_TransformStyle.js +53 -0
- package/Libraries/StyleSheet/processTransform.windows.js +272 -0
- package/Libraries/Text/Text.js +13 -7
- package/Libraries/Text/Text.windows.js +16 -7
- package/Libraries/Text/TextNativeComponent.js +2 -0
- package/Libraries/Text/TextProps.js +10 -0
- package/Libraries/Types/CoreEventTypes.js +13 -1
- package/Libraries/Types/CoreEventTypes.windows.js +26 -1
- package/Libraries/Utilities/Appearance.js +0 -8
- package/Libraries/Utilities/HMRClient.js +1 -1
- package/Libraries/Utilities/ReactNativeTestTools.js +1 -0
- package/Libraries/Utilities/codegenNativeComponent.js +17 -6
- package/Libraries/Utilities/stringifySafe.js +4 -1
- package/Libraries/Utilities/verifyComponentAttributeEquivalence.js +3 -3
- package/Libraries/WebSocket/WebSocket.js +1 -1
- package/Libraries/vendor/emitter/_EmitterSubscription.js +1 -1
- package/Libraries/vendor/emitter/_EventEmitter.js +1 -1
- package/Libraries/vendor/emitter/_EventSubscription.js +1 -1
- package/Microsoft.ReactNative/Base/CoreNativeModules.cpp +1 -4
- package/Microsoft.ReactNative/DynamicReader.cpp +3 -3
- package/Microsoft.ReactNative/Fabric/ComponentView.h +1 -0
- package/Microsoft.ReactNative/Fabric/ComponentViewRegistry.cpp +36 -2
- package/Microsoft.ReactNative/Fabric/ComponentViewRegistry.h +1 -0
- package/Microsoft.ReactNative/Fabric/DWriteHelpers.cpp +19 -0
- package/Microsoft.ReactNative/Fabric/DWriteHelpers.h +13 -0
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +65 -19
- package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +2 -0
- package/Microsoft.ReactNative/Fabric/ParagraphComponentView.cpp +36 -10
- package/Microsoft.ReactNative/Fabric/ScrollViewComponentView.cpp +2 -0
- package/Microsoft.ReactNative/Fabric/SliderComponentView.cpp +107 -0
- package/Microsoft.ReactNative/Fabric/SliderComponentView.h +51 -0
- package/Microsoft.ReactNative/Fabric/SwitchComponentView.cpp +109 -0
- package/Microsoft.ReactNative/Fabric/SwitchComponentView.h +52 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputComponentDescriptor.h +197 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputComponentView.cpp +308 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputComponentView.h +52 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputEventEmitter.cpp +31 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputEventEmitter.h +33 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputProps.cpp +81 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputProps.h +132 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputShadowNode.cpp +193 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputShadowNode.h +85 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputState.cpp +76 -0
- package/Microsoft.ReactNative/Fabric/TextInput/WindowsTextInputState.h +99 -0
- package/Microsoft.ReactNative/Fabric/ViewComponentView.cpp +35 -3
- package/Microsoft.ReactNative/Fabric/ViewComponentView.h +1 -0
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/rncore/EventEmitters.h +5 -0
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/rncore/Props.h +5 -0
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/slider/SliderMeasurementsManager.cpp +46 -0
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/slider/SliderMeasurementsManager.h +30 -0
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/Color.cpp +2 -0
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/conversions.h +1 -9
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/platform/cxx/react/renderer/graphics/Color.h +3 -1
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.cpp +119 -57
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.h +18 -1
- package/Microsoft.ReactNative/IViewManager.idl +3 -3
- package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +13 -107
- package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +2 -2
- package/Microsoft.ReactNative/Modules/AppStateModule.cpp +2 -0
- package/Microsoft.ReactNative/Modules/AppStateModule.h +2 -0
- package/Microsoft.ReactNative/Modules/CreateModules.cpp +3 -3
- package/Microsoft.ReactNative/Modules/NativeUIManager.cpp +7 -5
- package/Microsoft.ReactNative/Modules/TimingModule.cpp +2 -2
- package/Microsoft.ReactNative/Modules/TimingModule.h +2 -2
- package/Microsoft.ReactNative/ReactHost/{ReactContext.cpp → MsoReactContext.cpp} +1 -1
- package/Microsoft.ReactNative/ReactHost/{ReactContext.h → MsoReactContext.h} +0 -0
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +15 -2
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +1 -1
- package/Microsoft.ReactNative/ReactHost/ReactNativeHeaders.h +1 -1
- package/Microsoft.ReactNative/ReactInstanceSettings.idl +12 -2
- package/Microsoft.ReactNative/ReactPackageBuilder.cpp +1 -1
- package/Microsoft.ReactNative/ReactRootView.cpp +2 -1
- package/Microsoft.ReactNative/RedBox.cpp +3 -2
- package/Microsoft.ReactNative/TurboModulesProvider.cpp +3 -2
- package/Microsoft.ReactNative/TurboModulesProvider.h +4 -1
- package/Microsoft.ReactNative/Utils/LocalBundleReader.cpp +41 -0
- package/Microsoft.ReactNative/Utils/ValueUtils.cpp +3 -2
- package/Microsoft.ReactNative/Views/ControlViewManager.cpp +32 -0
- package/Microsoft.ReactNative/Views/ControlViewManager.h +11 -0
- package/Microsoft.ReactNative/Views/DevMenu.cpp +2 -2
- package/Microsoft.ReactNative/Views/FrameworkElementTransferProperties.cpp +13 -2
- package/Microsoft.ReactNative/Views/FrameworkElementViewManager.cpp +149 -22
- package/Microsoft.ReactNative/Views/Image/ImageViewManager.cpp +1 -1
- package/Microsoft.ReactNative/Views/Image/Microsoft.UI.Composition.Effects_Impl.h +5 -11
- package/Microsoft.ReactNative/Views/Image/ReactImage.cpp +2 -1
- package/Microsoft.ReactNative/Views/SliderViewManager.cpp +12 -4
- package/Microsoft.ReactNative/Views/TextInputViewManager.cpp +1 -1
- package/Microsoft.ReactNative/Views/TextViewManager.cpp +2 -2
- package/Microsoft.ReactNative/Views/TouchEventHandler.cpp +163 -37
- package/Microsoft.ReactNative/Views/TouchEventHandler.h +11 -4
- package/Microsoft.ReactNative/Views/ViewPanel.cpp +3 -23
- package/Microsoft.ReactNative/Views/ViewPanel.h +2 -3
- package/Microsoft.ReactNative/Views/ViewViewManager.cpp +21 -0
- package/Microsoft.ReactNative/XamlUIService.cpp +1 -1
- package/Microsoft.ReactNative/XamlView.h +8 -3
- package/Microsoft.ReactNative.Cxx/CppWinRTIncludes.h +3 -5
- package/Microsoft.ReactNative.Cxx/DesktopWindowBridge.h +1 -1
- package/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.cpp +11 -2
- package/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.h +1 -0
- package/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.cpp +19 -14
- package/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.h +4 -0
- package/Microsoft.ReactNative.Cxx/JSValueReader.h +2 -2
- package/Microsoft.ReactNative.Cxx/JSValueWriter.h +5 -5
- package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems +5 -1
- package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems.filters +2 -3
- package/Microsoft.ReactNative.Cxx/NativeModules.h +3 -3
- package/Microsoft.ReactNative.Cxx/ReactContext.h +3 -3
- package/Microsoft.ReactNative.Cxx/ReactNonAbiValue.h +3 -3
- package/Microsoft.ReactNative.Cxx/XamlUtils.h +44 -5
- package/Microsoft.ReactNative.Managed/Microsoft.ReactNative.Managed.csproj +0 -6
- package/Mso/activeObject/activeObject.h +2 -2
- package/Mso/compilerAdapters/cppMacros.h +3 -5
- package/Mso/errorCode/errorProvider.h +2 -2
- package/Mso/errorCode/maybe.h +4 -4
- package/Mso/functional/functor.h +6 -6
- package/Mso/functional/functorRef.h +2 -2
- package/Mso/future/details/executor.h +2 -2
- package/Mso/future/details/futureFuncInl.h +4 -4
- package/Mso/future/details/ifuture.h +3 -3
- package/Mso/future/details/maybeInvoker.h +6 -6
- package/Mso/future/details/promiseGroupInl.h +4 -4
- package/Mso/future/details/promiseInl.h +4 -4
- package/Mso/future/details/resultTraits.h +4 -4
- package/Mso/future/details/whenAllInl.h +1 -1
- package/Mso/future/future.h +13 -13
- package/Mso/guid/msoGuidDetails.h +1 -1
- package/Mso/memoryApi/memoryApi.h +13 -7
- package/Mso/motifCpp/gTestAdapter.h +1 -1
- package/Mso/motifCpp/testInfo.h +7 -9
- package/Mso/object/make.h +8 -8
- package/Mso/object/objectRefCount.h +3 -5
- package/Mso/object/objectWithWeakRef.h +10 -14
- package/Mso/object/queryCast.h +4 -4
- package/Mso/object/refCountedObject.h +4 -4
- package/Mso/object/unknownObject.h +7 -7
- package/Mso/platformAdapters/windowsFirst.h +1 -1
- package/Mso/smartPtr/cntPtr.h +8 -8
- package/Mso/src/dispatchQueue/threadPoolScheduler_win.cpp +96 -4
- package/Mso/src/dispatchQueue/uiScheduler_winrt.cpp +2 -2
- package/Mso/src/future/futureImpl.h +1 -1
- package/Mso/src/memoryApi/memoryApi.cpp +4 -4
- package/PropertySheets/CppAppConsumeCSharpModule.props +3 -0
- package/PropertySheets/External/Microsoft.ReactNative.WinAppSDK.CSharpApp.props +26 -0
- package/PropertySheets/External/Microsoft.ReactNative.WinAppSDK.Common.props +12 -0
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/PropertySheets/JSEngine.props +1 -1
- package/PropertySheets/React.Cpp.props +13 -0
- package/PropertySheets/WinUI.props +3 -6
- package/ReactCommon/ReactCommon.vcxproj +2 -4
- package/ReactCommon/ReactCommon.vcxproj.filters +4 -1
- package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/JSCRuntime.cpp +1480 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/decorator.h +753 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/jsi.h +1331 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/test/testlib.cpp +1431 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/bridging/CallbackWrapper.h +103 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core/ReactCommon/TurboModule.h +87 -0
- package/ReactCommon/TEMP_UntilReactCommonUpdate/react/nativemodule/core/ReactCommon/TurboModuleUtils.h +61 -0
- package/ReactCommon/Yoga.cpp +1 -1
- package/Scripts/{Microsoft.ReactNative.ProjectReunion.nuspec → Microsoft.ReactNative.WindowsAppSDK.nuspec} +7 -9
- package/Scripts/OfficeReact.Win32.nuspec +1 -3
- package/Scripts/Tfs/Layout-MSRN-Headers.ps1 +2 -1
- package/Scripts/copyRNLibraries.js +8 -8
- package/Scripts/just.js +1 -1
- package/Scripts/rnw-dependencies.ps1 +41 -10
- package/Scripts/run-desktop-integration-tests.js +6 -6
- package/Shared/AbiSafe.h +3 -3
- package/Shared/BaseScriptStoreImpl.cpp +1 -1
- package/Shared/CppRuntimeOptions.h +50 -0
- package/Shared/CreateModules.h +4 -0
- package/Shared/DevSupportManager.cpp +34 -33
- package/Shared/DevSupportManager.h +1 -2
- package/Shared/HermesRuntimeHolder.cpp +23 -14
- package/Shared/HermesRuntimeHolder.h +8 -2
- package/Shared/IDevSupportManager.h +1 -2
- package/Shared/InspectorPackagerConnection.cpp +7 -5
- package/Shared/InspectorPackagerConnection.h +2 -2
- package/Shared/JSI/ChakraApi.cpp +0 -1
- package/Shared/JSI/ChakraRuntime.cpp +1 -2
- package/Shared/JSI/NapiJsiV8RuntimeHolder.h +1 -1
- package/Shared/JSI/RuntimeHolder.h +2 -0
- package/Shared/Modules/HttpModule.cpp +198 -0
- package/Shared/Modules/HttpModule.h +53 -0
- package/Shared/Modules/WebSocketModule.cpp +5 -1
- package/Shared/Modules/WebSocketModule.h +8 -5
- package/Shared/Networking/IHttpResource.h +53 -0
- package/Shared/{IWebSocketResource.h → Networking/IWebSocketResource.h} +3 -3
- package/Shared/Networking/OriginPolicy.h +15 -0
- package/Shared/Networking/OriginPolicyHttpFilter.cpp +746 -0
- package/Shared/Networking/OriginPolicyHttpFilter.h +112 -0
- package/Shared/Networking/WinRTHttpResource.cpp +347 -0
- package/Shared/Networking/WinRTHttpResource.h +67 -0
- package/Shared/Networking/WinRTTypes.h +30 -0
- package/Shared/{WinRTWebSocketResource.cpp → Networking/WinRTWebSocketResource.cpp} +31 -22
- package/Shared/{WinRTWebSocketResource.h → Networking/WinRTWebSocketResource.h} +3 -3
- package/Shared/OInstance.cpp +37 -11
- package/Shared/RuntimeOptions.cpp +93 -15
- package/Shared/RuntimeOptions.h +22 -9
- package/Shared/Shared.vcxitems +126 -5
- package/Shared/Shared.vcxitems.filters +55 -15
- package/Shared/Threading/BatchingQueueThread.cpp +1 -1
- package/Shared/Utils/WinRTConversions.cpp +22 -0
- package/Shared/Utils/WinRTConversions.h +15 -0
- package/Shared/tracing/fbsystrace.h +2 -2
- package/codegen/NativeActionSheetManagerSpec.g.h +6 -0
- package/codegen/NativeAnimatedModuleSpec.g.h +43 -37
- package/codegen/NativeAnimatedTurboModuleSpec.g.h +43 -37
- package/codegen/NativePushNotificationManagerIOSSpec.g.h +2 -0
- package/codegen/react/components/rnwcore/ComponentDescriptors.h +0 -1
- package/codegen/react/components/rnwcore/EventEmitters.cpp +133 -0
- package/codegen/react/components/rnwcore/EventEmitters.h +0 -18
- package/codegen/react/components/rnwcore/Props.cpp +0 -13
- package/codegen/react/components/rnwcore/Props.h +0 -16
- package/codegen/react/components/rnwcore/ShadowNodes.cpp +0 -1
- package/codegen/react/components/rnwcore/ShadowNodes.h +0 -10
- package/include/Shared/cdebug.h +9 -9
- package/index.js +30 -25
- package/index.windows.js +30 -25
- package/jest/preprocessor.js +24 -107
- package/jest/preprocessor_DO_NOT_USE.js +122 -0
- package/metro.config.js +3 -70
- package/package.json +29 -28
- package/react-native.config.js +40 -6
- package/rntypes/index.d.ts +19 -7
- package/stubs/glog/logging.h +1 -1
- package/template/cpp-app/src/App.h +0 -4
- package/template/cs-app/src/App.xaml.cs +0 -5
- package/template/cs-app/src/MainPage.xaml.cs +1 -10
- package/template/cs-app-WinAppSDK/MyApp/App.xaml +16 -0
- package/template/cs-app-WinAppSDK/MyApp/App.xaml.cs +70 -0
- package/template/cs-app-WinAppSDK/MyApp/MainWindow.xaml +14 -0
- package/template/cs-app-WinAppSDK/MyApp/MainWindow.xaml.cs +38 -0
- package/template/cs-app-WinAppSDK/MyApp/Package.appxmanifest +48 -0
- package/template/cs-app-WinAppSDK/MyApp/Properties/PublishProfiles/win10-arm64.pubxml +19 -0
- package/template/cs-app-WinAppSDK/MyApp/Properties/PublishProfiles/win10-x64.pubxml +19 -0
- package/template/cs-app-WinAppSDK/MyApp/Properties/PublishProfiles/win10-x86.pubxml +19 -0
- package/template/cs-app-WinAppSDK/MyApp/Properties/launchSettings.json +10 -0
- package/template/cs-app-WinAppSDK/MyApp/app.manifest +15 -0
- package/template/cs-app-WinAppSDK/proj/ExperimentalFeatures.props +23 -0
- package/template/cs-app-WinAppSDK/proj/MyApp.csproj +49 -0
- package/template/cs-app-WinAppSDK/proj/MyApp.sln +43 -0
- package/template/cs-app-WinAppSDK/proj/NuGet.Config +17 -0
- package/template/metro.devMode.config.js +2 -51
- package/typings-index.js +5 -1
- package/typings-index.js.map +1 -1
- package/Libraries/Components/SegmentedControlIOS/RCTSegmentedControlNativeComponent.js +0 -44
- package/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js +0 -45
- package/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js +0 -123
- package/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.windows.js +0 -45
- package/Libraries/Components/View/ReactNativeViewViewConfig.js +0 -360
- package/Libraries/Components/View/ReactNativeViewViewConfig.windows.js +0 -390
- package/Libraries/Components/View/ReactNativeViewViewConfigAndroid.js +0 -83
- package/Libraries/ReactNative/UIManagerInjection.js +0 -15
- package/Libraries/Renderer/implementations/ReactFabric-dev.fb.js +0 -24527
- package/Libraries/Renderer/implementations/ReactFabric-prod.fb.js +0 -8309
- package/Libraries/Renderer/implementations/ReactFabric-profiling.fb.js +0 -8961
- package/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js +0 -24948
- package/Libraries/Renderer/implementations/ReactNativeRenderer-prod.fb.js +0 -8400
- package/Libraries/Renderer/implementations/ReactNativeRenderer-profiling.fb.js +0 -9049
- package/PropertySheets/CppEnablePackageReferences.props +0 -13
- package/Shared/IHttpResource.h +0 -34
- package/Shared/cdebug.cpp +0 -6
- package/include/Shared/ViewManager.h +0 -34
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
#include "OriginPolicyHttpFilter.h"
|
|
5
|
+
|
|
6
|
+
// React Native Windows
|
|
7
|
+
#include <CppRuntimeOptions.h>
|
|
8
|
+
#include "WinRTTypes.h"
|
|
9
|
+
|
|
10
|
+
// Boost Library
|
|
11
|
+
#include <boost/algorithm/string.hpp>
|
|
12
|
+
#include <boost/lexical_cast/try_lexical_convert.hpp>
|
|
13
|
+
|
|
14
|
+
// Windows API
|
|
15
|
+
#include <winrt/Windows.Web.Http.Headers.h>
|
|
16
|
+
|
|
17
|
+
// Standard Library
|
|
18
|
+
#include <queue>
|
|
19
|
+
#include <regex>
|
|
20
|
+
|
|
21
|
+
using std::set;
|
|
22
|
+
using std::wstring;
|
|
23
|
+
|
|
24
|
+
using winrt::hresult_error;
|
|
25
|
+
using winrt::hstring;
|
|
26
|
+
using winrt::to_hstring;
|
|
27
|
+
using winrt::Windows::Foundation::IInspectable;
|
|
28
|
+
using winrt::Windows::Foundation::IPropertyValue;
|
|
29
|
+
using winrt::Windows::Foundation::Uri;
|
|
30
|
+
using winrt::Windows::Web::Http::HttpMethod;
|
|
31
|
+
using winrt::Windows::Web::Http::HttpRequestMessage;
|
|
32
|
+
using winrt::Windows::Web::Http::HttpResponseMessage;
|
|
33
|
+
using winrt::Windows::Web::Http::Filters::IHttpBaseProtocolFilter;
|
|
34
|
+
using winrt::Windows::Web::Http::Filters::IHttpFilter;
|
|
35
|
+
using winrt::Windows::Web::Http::Headers::HttpMediaTypeHeaderValue;
|
|
36
|
+
using winrt::Windows::Web::Http::Headers::HttpRequestHeaderCollection;
|
|
37
|
+
|
|
38
|
+
namespace Microsoft::React::Networking {
|
|
39
|
+
|
|
40
|
+
#pragma region OriginPolicyHttpFilter
|
|
41
|
+
|
|
42
|
+
#pragma region ConstWcharComparer
|
|
43
|
+
|
|
44
|
+
bool OriginPolicyHttpFilter::ConstWcharComparer::operator()(const wchar_t *a, const wchar_t *b) const {
|
|
45
|
+
return _wcsicmp(a, b) < 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#pragma endregion ConstWcharComparer
|
|
49
|
+
|
|
50
|
+
// https://fetch.spec.whatwg.org/#forbidden-method
|
|
51
|
+
/*static*/ set<const wchar_t *, OriginPolicyHttpFilter::ConstWcharComparer> OriginPolicyHttpFilter::s_forbiddenMethods =
|
|
52
|
+
{L"CONNECT", L"TRACE", L"TRACK"};
|
|
53
|
+
|
|
54
|
+
/*static*/ set<const wchar_t *, OriginPolicyHttpFilter::ConstWcharComparer>
|
|
55
|
+
OriginPolicyHttpFilter::s_simpleCorsMethods = {L"GET", L"HEAD", L"POST"};
|
|
56
|
+
|
|
57
|
+
/*static*/ set<const wchar_t *, OriginPolicyHttpFilter::ConstWcharComparer>
|
|
58
|
+
OriginPolicyHttpFilter::s_simpleCorsRequestHeaderNames = {
|
|
59
|
+
L"Accept",
|
|
60
|
+
L"Accept-Language",
|
|
61
|
+
L"Content-Language",
|
|
62
|
+
L"Content-Type",
|
|
63
|
+
L"DPR",
|
|
64
|
+
L"Downlink",
|
|
65
|
+
L"Save-Data",
|
|
66
|
+
L"Viewport-Width",
|
|
67
|
+
L"Width"};
|
|
68
|
+
|
|
69
|
+
/*static*/ set<const wchar_t *, OriginPolicyHttpFilter::ConstWcharComparer>
|
|
70
|
+
OriginPolicyHttpFilter::s_simpleCorsResponseHeaderNames =
|
|
71
|
+
{L"Cache-Control", L"Content-Language", L"Content-Type", L"Expires", L"Last-Modified", L"Pragma"};
|
|
72
|
+
|
|
73
|
+
/*static*/ set<const wchar_t *, OriginPolicyHttpFilter::ConstWcharComparer>
|
|
74
|
+
OriginPolicyHttpFilter::s_simpleCorsContentTypeValues = {
|
|
75
|
+
L"application/x-www-form-urlencoded",
|
|
76
|
+
L"multipart/form-data",
|
|
77
|
+
L"text/plain"};
|
|
78
|
+
|
|
79
|
+
// https://fetch.spec.whatwg.org/#forbidden-header-name
|
|
80
|
+
// Chromium still bans "User-Agent" due to https://crbug.com/571722
|
|
81
|
+
/*static*/ set<const wchar_t *, OriginPolicyHttpFilter::ConstWcharComparer>
|
|
82
|
+
OriginPolicyHttpFilter::s_corsForbiddenRequestHeaderNames = {
|
|
83
|
+
L"Accept-Charset",
|
|
84
|
+
L"Accept-Encoding",
|
|
85
|
+
L"Access-Control-Request-Headers",
|
|
86
|
+
L"Access-Control-Request-Method",
|
|
87
|
+
L"Connection",
|
|
88
|
+
L"Content-Length",
|
|
89
|
+
L"Cookie",
|
|
90
|
+
L"Cookie2",
|
|
91
|
+
L"Date",
|
|
92
|
+
L"DNT",
|
|
93
|
+
L"Expect",
|
|
94
|
+
L"Host",
|
|
95
|
+
L"Keep-Alive",
|
|
96
|
+
L"Origin",
|
|
97
|
+
L"Referer",
|
|
98
|
+
L"TE",
|
|
99
|
+
L"Trailer",
|
|
100
|
+
L"Transfer-Encoding",
|
|
101
|
+
L"Upgrade",
|
|
102
|
+
L"Via"};
|
|
103
|
+
|
|
104
|
+
/*static*/ set<const wchar_t *, OriginPolicyHttpFilter::ConstWcharComparer>
|
|
105
|
+
OriginPolicyHttpFilter::s_cookieSettingResponseHeaders = {
|
|
106
|
+
L"Set-Cookie",
|
|
107
|
+
L"Set-Cookie2", // Deprecated by the spec, but probably still used
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/*static*/ set<const wchar_t *, OriginPolicyHttpFilter::ConstWcharComparer>
|
|
111
|
+
OriginPolicyHttpFilter::s_corsForbiddenRequestHeaderNamePrefixes = {L"Proxy-", L"Sec-"};
|
|
112
|
+
|
|
113
|
+
/*static*/ Uri OriginPolicyHttpFilter::s_origin{nullptr};
|
|
114
|
+
|
|
115
|
+
/*static*/ void OriginPolicyHttpFilter::SetStaticOrigin(std::string &&url) {
|
|
116
|
+
if (!url.empty())
|
|
117
|
+
s_origin = Uri{to_hstring(url)};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/*static*/ bool OriginPolicyHttpFilter::IsSameOrigin(Uri const &u1, Uri const &u2) noexcept {
|
|
121
|
+
return u1.SchemeName() == u2.SchemeName() && u1.Host() == u2.Host() && u1.Port() == u2.Port();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/*static*/ bool OriginPolicyHttpFilter::IsSimpleCorsRequest(HttpRequestMessage const &request) noexcept {
|
|
125
|
+
// Ensure header is in Simple CORS white list
|
|
126
|
+
for (const auto &header : request.Headers()) {
|
|
127
|
+
if (s_simpleCorsRequestHeaderNames.find(header.Key().c_str()) == s_simpleCorsRequestHeaderNames.cend())
|
|
128
|
+
return false;
|
|
129
|
+
|
|
130
|
+
// Ensure Content-Type value is in Simple CORS white list, if present
|
|
131
|
+
if (boost::iequals(header.Key(), L"Content-Type")) {
|
|
132
|
+
if (s_simpleCorsContentTypeValues.find(header.Value().c_str()) != s_simpleCorsContentTypeValues.cend())
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// WinRT separates request headers from request content headers
|
|
138
|
+
if (auto content = request.Content()) {
|
|
139
|
+
for (const auto &header : content.Headers()) {
|
|
140
|
+
// WinRT automatically appends non-whitelisted header Content-Length when Content-Type is set. Skip it.
|
|
141
|
+
if (s_simpleCorsRequestHeaderNames.find(header.Key().c_str()) == s_simpleCorsRequestHeaderNames.cend() &&
|
|
142
|
+
!boost::iequals(header.Key(), "Content-Length"))
|
|
143
|
+
return false;
|
|
144
|
+
|
|
145
|
+
// Ensure Content-Type value is in Simple CORS white list, if present
|
|
146
|
+
if (boost::iequals(header.Key(), L"Content-Type")) {
|
|
147
|
+
if (s_simpleCorsContentTypeValues.find(header.Value().c_str()) == s_simpleCorsContentTypeValues.cend())
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Ensure method is in Simple CORS white list
|
|
154
|
+
return s_simpleCorsMethods.find(request.Method().ToString().c_str()) != s_simpleCorsMethods.cend();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/*static*/ Uri OriginPolicyHttpFilter::GetOrigin(Uri const &uri) noexcept {
|
|
158
|
+
return Uri{uri.SchemeName() + L"://" + uri.Host() + L":" + to_hstring(uri.Port())};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/*static*/ bool OriginPolicyHttpFilter::AreSafeRequestHeaders(
|
|
162
|
+
winrt::Windows::Web::Http::Headers::HttpRequestHeaderCollection const &headers) noexcept {
|
|
163
|
+
for (const auto &header : headers) {
|
|
164
|
+
if (s_corsForbiddenRequestHeaderNames.find(header.Key().c_str()) != s_corsForbiddenRequestHeaderNames.cend())
|
|
165
|
+
return false;
|
|
166
|
+
|
|
167
|
+
for (const auto &prefix : s_corsForbiddenRequestHeaderNamePrefixes) {
|
|
168
|
+
if (boost::istarts_with(header.Key(), prefix))
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// See https://fetch.spec.whatwg.org/#cors-safelisted-request-header
|
|
177
|
+
// "A CORS-safelisted header is a header whose name is either one of 'Accept', 'Accept-Language', and
|
|
178
|
+
// 'Content-Language', or whose name is 'Content-Type' and value is one of 'application/x-www-form-urlencoded',
|
|
179
|
+
// 'multipart/form-data', and 'text/plain'
|
|
180
|
+
/*static*/ bool OriginPolicyHttpFilter::IsCorsSafelistedRequestHeader(
|
|
181
|
+
hstring const &name,
|
|
182
|
+
hstring const &value) noexcept {
|
|
183
|
+
// 1. If value's length is greater than 128, then return false.
|
|
184
|
+
if (value.size() > 128)
|
|
185
|
+
return false;
|
|
186
|
+
|
|
187
|
+
// 2. Byte-lowercase name and switch on the result:
|
|
188
|
+
static const wchar_t *const safeHeaderNames[] = {
|
|
189
|
+
// The following four headers are from the CORS spec
|
|
190
|
+
L"accept",
|
|
191
|
+
L"accept-language",
|
|
192
|
+
L"content-language",
|
|
193
|
+
L"content-type",
|
|
194
|
+
|
|
195
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Save-Data
|
|
196
|
+
L"save-data",
|
|
197
|
+
|
|
198
|
+
// https://w3c.github.io/device-memory/#sec-device-memory-client-hint-header
|
|
199
|
+
L"device-memory",
|
|
200
|
+
L"dpr",
|
|
201
|
+
L"width",
|
|
202
|
+
L"viewport-width",
|
|
203
|
+
|
|
204
|
+
// https://tools.ietf.org/html/draft-west-lang-client-hint
|
|
205
|
+
L"sec-ch-lang",
|
|
206
|
+
|
|
207
|
+
// https://tools.ietf.org/html/draft-west-ua-client-hints
|
|
208
|
+
L"sec-ch-ua",
|
|
209
|
+
L"sec-ch-ua-platform",
|
|
210
|
+
L"sec-ch-ua-arch",
|
|
211
|
+
L"sec-ch-ua-model",
|
|
212
|
+
L"sec-ch-ua-mobile",
|
|
213
|
+
L"sec-ch-ua-full-version",
|
|
214
|
+
L"sec-ch-ua-platform-version",
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
auto nameLower = boost::to_lower_copy(wstring{name.c_str()});
|
|
218
|
+
if (std::find(std::cbegin(safeHeaderNames), std::cend(safeHeaderNames), nameLower) == std::end(safeHeaderNames))
|
|
219
|
+
return false;
|
|
220
|
+
|
|
221
|
+
double doubleHolder;
|
|
222
|
+
if (nameLower == L"device-memory" || nameLower == L"dpr")
|
|
223
|
+
return boost::conversion::try_lexical_convert<double, wstring>(value.c_str(), doubleHolder);
|
|
224
|
+
|
|
225
|
+
int intHolder;
|
|
226
|
+
if (nameLower == L"width" || nameLower == L"viewport-width")
|
|
227
|
+
return boost::conversion::try_lexical_convert<int, wstring>(value.c_str(), intHolder);
|
|
228
|
+
|
|
229
|
+
auto valueLower = boost::to_lower_copy(wstring{value.c_str()});
|
|
230
|
+
if (nameLower == L"save-data")
|
|
231
|
+
return valueLower == L"on";
|
|
232
|
+
|
|
233
|
+
if (nameLower == L"accept")
|
|
234
|
+
return !std::any_of(valueLower.cbegin(), valueLower.cend(), IsCorsUnsafeRequestHeaderByte);
|
|
235
|
+
|
|
236
|
+
if (nameLower == L"accept-language" || nameLower == L"content-language") {
|
|
237
|
+
return std::all_of(valueLower.cbegin(), valueLower.cend(), [](wchar_t c) noexcept {
|
|
238
|
+
return (0x30 <= c && c <= 0x39) || // 0-9
|
|
239
|
+
(0x41 <= c && c <= 0x5A) || // A-Z
|
|
240
|
+
(0x61 <= c && c <= 0x7A) || // a-z
|
|
241
|
+
c == 0x20 || c == 0x2A || c == 0x2C || c == 0x2D || c == 0x2E || c == 0x3B || c == 0x3D; // *,-.;=
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (nameLower == L"content-type") {
|
|
246
|
+
if (std::any_of(valueLower.cbegin(), valueLower.cend(), IsCorsUnsafeRequestHeaderByte))
|
|
247
|
+
return false;
|
|
248
|
+
|
|
249
|
+
// https://mimesniff.spec.whatwg.org/#parse-a-mime-type
|
|
250
|
+
HttpMediaTypeHeaderValue mediaType{nullptr};
|
|
251
|
+
if (HttpMediaTypeHeaderValue::TryParse(valueLower, mediaType))
|
|
252
|
+
return mediaType.ToString() == L"application/x-www-form-urlencoded" ||
|
|
253
|
+
mediaType.ToString() == L"multipart/form-data" || mediaType.ToString() == L"text/plain";
|
|
254
|
+
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte
|
|
262
|
+
/*static*/ bool OriginPolicyHttpFilter::IsCorsUnsafeRequestHeaderByte(wchar_t c) noexcept {
|
|
263
|
+
return (c < 0x20 && c != 0x09) || c == 0x22 || c == 0x28 || c == 0x29 || c == 0x3a || c == 0x3c || c == 0x3e ||
|
|
264
|
+
c == 0x3f || c == 0x40 || c == 0x5b || c == 0x5c || c == 0x5d || c == 0x7b || c == 0x7d || c == 0x7f;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/*static*/ set<const wchar_t *> OriginPolicyHttpFilter::CorsUnsafeNotForbiddenRequestHeaderNames(
|
|
268
|
+
HttpRequestHeaderCollection const &headers) noexcept {
|
|
269
|
+
constexpr size_t maxSafelistValueSize = 1024;
|
|
270
|
+
size_t safelistValueSize = 0;
|
|
271
|
+
std::vector<const wchar_t *> potentiallyUnsafeNames;
|
|
272
|
+
set<const wchar_t *> result;
|
|
273
|
+
for (const auto &header : headers) {
|
|
274
|
+
const auto headerName = header.Key().c_str();
|
|
275
|
+
|
|
276
|
+
// If header is not safe
|
|
277
|
+
if (boost::istarts_with(headerName, L"Proxy-") || boost::istarts_with(headerName, L"Sec-") ||
|
|
278
|
+
s_corsForbiddenRequestHeaderNames.find(headerName) != s_corsForbiddenRequestHeaderNames.cend())
|
|
279
|
+
continue;
|
|
280
|
+
|
|
281
|
+
if (!IsCorsSafelistedRequestHeader(header.Key(), header.Value())) {
|
|
282
|
+
result.emplace(header.Key().c_str());
|
|
283
|
+
} else {
|
|
284
|
+
potentiallyUnsafeNames.emplace_back(std::wstring_view{header.Key()}.data());
|
|
285
|
+
safelistValueSize += header.Value().size();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (safelistValueSize > maxSafelistValueSize)
|
|
290
|
+
result.insert(potentiallyUnsafeNames.begin(), potentiallyUnsafeNames.end());
|
|
291
|
+
|
|
292
|
+
return result;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/*static*/ OriginPolicyHttpFilter::AccessControlValues OriginPolicyHttpFilter::ExtractAccessControlValues(
|
|
296
|
+
winrt::Windows::Foundation::Collections::IMap<hstring, hstring> const &headers) {
|
|
297
|
+
using std::wregex;
|
|
298
|
+
using std::wsregex_token_iterator;
|
|
299
|
+
|
|
300
|
+
// https://tools.ietf.org/html/rfc2616#section-4.2
|
|
301
|
+
wregex rgx{L"\\s*,\\s*"};
|
|
302
|
+
AccessControlValues result;
|
|
303
|
+
|
|
304
|
+
auto ciStrCmp = [](const wstring &a, const wstring &b) { return _wcsicmp(a.c_str(), b.c_str()) < 0; };
|
|
305
|
+
set<wstring, decltype(ciStrCmp)> allowedHeaders{ciStrCmp};
|
|
306
|
+
set<wstring, decltype(ciStrCmp)> allowedMethods{ciStrCmp};
|
|
307
|
+
set<wstring, decltype(ciStrCmp)> exposedHeaders{ciStrCmp};
|
|
308
|
+
|
|
309
|
+
for (const auto &header : headers) {
|
|
310
|
+
if (boost::iequals(header.Key(), L"Access-Control-Allow-Headers")) {
|
|
311
|
+
auto value = wstring{header.Value().c_str()};
|
|
312
|
+
|
|
313
|
+
// TODO: Avoid redundant comparison.
|
|
314
|
+
auto parsed = set<wstring, decltype(ciStrCmp)>{
|
|
315
|
+
wsregex_token_iterator{value.cbegin(), value.cend(), rgx, -1}, wsregex_token_iterator{}, ciStrCmp};
|
|
316
|
+
allowedHeaders.insert(parsed.cbegin(), parsed.cend());
|
|
317
|
+
result.AllowedHeaders.insert(allowedHeaders.cbegin(), allowedHeaders.cend());
|
|
318
|
+
} else if (boost::iequals(header.Key(), L"Access-Control-Allow-Methods")) {
|
|
319
|
+
auto value = wstring{header.Value().c_str()};
|
|
320
|
+
|
|
321
|
+
// TODO: Avoid redundant comparison.
|
|
322
|
+
auto parsed = set<wstring, decltype(ciStrCmp)>{
|
|
323
|
+
wsregex_token_iterator{value.cbegin(), value.cend(), rgx, -1}, wsregex_token_iterator{}, ciStrCmp};
|
|
324
|
+
allowedMethods.insert(parsed.cbegin(), parsed.cend());
|
|
325
|
+
result.AllowedMethods.insert(allowedMethods.cbegin(), allowedMethods.cend());
|
|
326
|
+
} else if (boost::iequals(header.Key(), L"Access-Control-Allow-Origin")) {
|
|
327
|
+
result.AllowedOrigin = header.Value();
|
|
328
|
+
} else if (boost::iequals(header.Key(), L"Access-Control-Expose-Headers")) {
|
|
329
|
+
auto value = wstring{header.Value().c_str()};
|
|
330
|
+
|
|
331
|
+
// TODO: Avoid redundant comparison.
|
|
332
|
+
auto parsed = set<wstring, decltype(ciStrCmp)>{
|
|
333
|
+
wsregex_token_iterator{value.cbegin(), value.cend(), rgx, -1}, wsregex_token_iterator{}, ciStrCmp};
|
|
334
|
+
exposedHeaders.insert(parsed.cbegin(), parsed.cend());
|
|
335
|
+
result.ExposedHeaders.insert(exposedHeaders.cbegin(), exposedHeaders.cend());
|
|
336
|
+
} else if (boost::iequals(header.Key(), L"Access-Control-Allow-Credentials")) {
|
|
337
|
+
result.AllowedCredentials = header.Value();
|
|
338
|
+
} else if (boost::iequals(header.Key(), L"Access-Control-Max-Age")) {
|
|
339
|
+
result.MaxAge = _wtoi(header.Value().c_str());
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return result;
|
|
344
|
+
} // ExtractAccessControlValues
|
|
345
|
+
|
|
346
|
+
/*static*/ void OriginPolicyHttpFilter::RemoveHttpOnlyCookiesFromResponseHeaders(
|
|
347
|
+
HttpResponseMessage const &response,
|
|
348
|
+
bool removeAll) {
|
|
349
|
+
// Example: "Set-Cookie", L"id=a3fWa; Expires=Wed, 21 Oct 2020 07:28:00 GMT; HttpOnly"
|
|
350
|
+
std::queue<hstring> httpOnlyCookies;
|
|
351
|
+
for (const auto &header : response.Headers()) {
|
|
352
|
+
if (s_cookieSettingResponseHeaders.find(header.Key().c_str()) == s_cookieSettingResponseHeaders.cend())
|
|
353
|
+
continue;
|
|
354
|
+
|
|
355
|
+
if (removeAll) {
|
|
356
|
+
httpOnlyCookies.push(header.Key());
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Anchors (^$) can't be part of bracket expressions ([]).
|
|
361
|
+
// Create 3 matching groups: 1. Beginning of string 2. Between delimiters 3. End of string
|
|
362
|
+
const std::wregex re(L"(^HttpOnly\\s*;)|(;\\s*HttpOnly\\s*;)|(;\\s*HttpOnly$)", std::regex_constants::icase);
|
|
363
|
+
if (!std::regex_search(header.Value().c_str(), re))
|
|
364
|
+
continue;
|
|
365
|
+
|
|
366
|
+
// HttpOnly cookie detected. Removing.
|
|
367
|
+
httpOnlyCookies.push(header.Key());
|
|
368
|
+
} // const auto &header : response.Headers()
|
|
369
|
+
|
|
370
|
+
while (!httpOnlyCookies.empty()) {
|
|
371
|
+
response.Headers().Remove(httpOnlyCookies.front());
|
|
372
|
+
httpOnlyCookies.pop();
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
OriginPolicyHttpFilter::OriginPolicyHttpFilter(IHttpFilter &&innerFilter) : m_innerFilter{std::move(innerFilter)} {}
|
|
377
|
+
|
|
378
|
+
OriginPolicyHttpFilter::OriginPolicyHttpFilter()
|
|
379
|
+
: OriginPolicyHttpFilter(winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter{}) {}
|
|
380
|
+
|
|
381
|
+
OriginPolicy OriginPolicyHttpFilter::ValidateRequest(HttpRequestMessage const &request) {
|
|
382
|
+
auto effectiveOriginPolicy =
|
|
383
|
+
static_cast<OriginPolicy>(request.Properties().Lookup(L"OriginPolicy").as<IPropertyValue>().GetUInt64());
|
|
384
|
+
switch (effectiveOriginPolicy) {
|
|
385
|
+
case OriginPolicy::None:
|
|
386
|
+
return effectiveOriginPolicy;
|
|
387
|
+
|
|
388
|
+
case OriginPolicy::SameOrigin:
|
|
389
|
+
if (!IsSameOrigin(s_origin, request.RequestUri()))
|
|
390
|
+
throw hresult_error{E_INVALIDARG, L"SOP (same-origin policy) is enforced"};
|
|
391
|
+
break;
|
|
392
|
+
|
|
393
|
+
case OriginPolicy::SimpleCrossOriginResourceSharing:
|
|
394
|
+
// Check for disallowed mixed content
|
|
395
|
+
if (GetRuntimeOptionBool("Http.BlockMixedContentSimpleCors") &&
|
|
396
|
+
s_origin.SchemeName() != request.RequestUri().SchemeName())
|
|
397
|
+
throw hresult_error{E_INVALIDARG, L"The origin and request URLs must have the same scheme"};
|
|
398
|
+
|
|
399
|
+
if (IsSameOrigin(s_origin, request.RequestUri()))
|
|
400
|
+
// Same origin. Therefore, skip Cross-Origin handling.
|
|
401
|
+
effectiveOriginPolicy = OriginPolicy::SameOrigin;
|
|
402
|
+
else if (!IsSimpleCorsRequest(request))
|
|
403
|
+
throw hresult_error{
|
|
404
|
+
E_INVALIDARG,
|
|
405
|
+
L"The request does not meet the requirements for Same-Origin policy or Simple Cross-Origin resource sharing"};
|
|
406
|
+
break;
|
|
407
|
+
|
|
408
|
+
case OriginPolicy::CrossOriginResourceSharing:
|
|
409
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
|
|
410
|
+
// Refer to CorsURLLoaderFactory::IsValidRequest in chrome\src\services\network\cors\cors_url_loader_factory.cc.
|
|
411
|
+
// Forbidden headers should be blocked regardless of origins.
|
|
412
|
+
// Example: On the Edge browser, an XHR request with the "Host" header set gets rejected as unsafe.
|
|
413
|
+
// https://fetch.spec.whatwg.org/#forbidden-header-name
|
|
414
|
+
|
|
415
|
+
if (s_origin.SchemeName() != request.RequestUri().SchemeName())
|
|
416
|
+
throw hresult_error{E_INVALIDARG, L"The origin and request URLs must have the same scheme"};
|
|
417
|
+
|
|
418
|
+
if (!AreSafeRequestHeaders(request.Headers()))
|
|
419
|
+
throw hresult_error{E_INVALIDARG, L"Request header not allowed in cross-origin resource sharing"};
|
|
420
|
+
|
|
421
|
+
if (s_forbiddenMethods.find(request.Method().ToString().c_str()) != s_forbiddenMethods.cend())
|
|
422
|
+
throw hresult_error{E_INVALIDARG, L"Request method not allowed in cross-origin resource sharing"};
|
|
423
|
+
|
|
424
|
+
if (IsSameOrigin(s_origin, request.RequestUri()))
|
|
425
|
+
effectiveOriginPolicy = OriginPolicy::SameOrigin;
|
|
426
|
+
else if (IsSimpleCorsRequest(request))
|
|
427
|
+
effectiveOriginPolicy = OriginPolicy::SimpleCrossOriginResourceSharing;
|
|
428
|
+
else
|
|
429
|
+
effectiveOriginPolicy = OriginPolicy::CrossOriginResourceSharing;
|
|
430
|
+
|
|
431
|
+
break;
|
|
432
|
+
|
|
433
|
+
default:
|
|
434
|
+
throw hresult_error{
|
|
435
|
+
E_INVALIDARG, L"Invalid OriginPolicy type: " + to_hstring(static_cast<size_t>(effectiveOriginPolicy))};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return effectiveOriginPolicy;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// See https://fetch.spec.whatwg.org/#cors-check
|
|
442
|
+
void OriginPolicyHttpFilter::ValidateAllowOrigin(
|
|
443
|
+
hstring const &allowedOrigin,
|
|
444
|
+
hstring const &allowCredentials,
|
|
445
|
+
IInspectable const &iRequestArgs) const {
|
|
446
|
+
// 4.10.1-2 - null allow origin
|
|
447
|
+
if (L"null" == allowedOrigin)
|
|
448
|
+
throw hresult_error{
|
|
449
|
+
E_INVALIDARG,
|
|
450
|
+
L"Response header Access-Control-Allow-Origin has a value of [null] which differs from the supplied origin"};
|
|
451
|
+
|
|
452
|
+
bool withCredentials = iRequestArgs.as<RequestArgs>()->WithCredentials;
|
|
453
|
+
// 4.10.3 - valid wild card allow origin
|
|
454
|
+
if (!withCredentials && L"*" == allowedOrigin)
|
|
455
|
+
return;
|
|
456
|
+
|
|
457
|
+
// We assume the source (request) origin is not "*", "null", or empty string. Valid URI is expected
|
|
458
|
+
// 4.10.4 - Mismatched allow origin
|
|
459
|
+
if (allowedOrigin.empty() || !IsSameOrigin(s_origin, Uri{allowedOrigin})) {
|
|
460
|
+
hstring errorMessage;
|
|
461
|
+
if (allowedOrigin.empty())
|
|
462
|
+
errorMessage = L"No valid origin in response";
|
|
463
|
+
|
|
464
|
+
// See https://fetch.spec.whatwg.org/#http-access-control-allow-origin.
|
|
465
|
+
else if (boost::contains(allowedOrigin, L" ,"))
|
|
466
|
+
errorMessage = L"Response header Access-Control-Allow-Origin can not have multiple values";
|
|
467
|
+
|
|
468
|
+
// A wildcard Access-Control-Allow-Origin can not be used if credentials are to be sent,
|
|
469
|
+
// even with Access-Control-Allow-Credentials set to true
|
|
470
|
+
// See https://fetch.spec.whatwg.org/#cors-protocol-and-credentials
|
|
471
|
+
else if (L"*" == allowedOrigin)
|
|
472
|
+
errorMessage =
|
|
473
|
+
L"Response header Access-Control-Allow-Origin can not have a wildcard value when the request includes credentials";
|
|
474
|
+
|
|
475
|
+
else
|
|
476
|
+
errorMessage = L"The Access-Control-Allow-Origin header has a value of [" + allowedOrigin +
|
|
477
|
+
L"] which differs from the supplied origin";
|
|
478
|
+
|
|
479
|
+
throw hresult_error{E_INVALIDARG, errorMessage};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// 4.10.5
|
|
483
|
+
if (!withCredentials)
|
|
484
|
+
return;
|
|
485
|
+
|
|
486
|
+
// 4.10.6-8
|
|
487
|
+
// https://fetch.spec.whatwg.org/#http-access-control-allow-credentials
|
|
488
|
+
// This check should be case sensitive.
|
|
489
|
+
// See also https://fetch.spec.whatwg.org/#http-new-header-syntax
|
|
490
|
+
if (L"true" != allowCredentials)
|
|
491
|
+
throw hresult_error{
|
|
492
|
+
E_INVALIDARG,
|
|
493
|
+
L"Access-Control-Allow-Credentials value must be \"true\" when the response includes credentials"};
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
void OriginPolicyHttpFilter::ValidatePreflightResponse(
|
|
497
|
+
HttpRequestMessage const &request,
|
|
498
|
+
HttpResponseMessage const &response) const {
|
|
499
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSExternalRedirectNotAllowed
|
|
500
|
+
using winrt::Windows::Web::Http::HttpStatusCode;
|
|
501
|
+
switch (response.StatusCode()) {
|
|
502
|
+
case HttpStatusCode::MovedPermanently:
|
|
503
|
+
case HttpStatusCode::TemporaryRedirect:
|
|
504
|
+
case HttpStatusCode::PermanentRedirect:
|
|
505
|
+
throw hresult_error{INET_E_REDIRECTING, L"Redirect is not allowed in a preflight request"};
|
|
506
|
+
|
|
507
|
+
default:
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
auto controlValues = ExtractAccessControlValues(response.Headers());
|
|
512
|
+
|
|
513
|
+
auto iRequestArgs = request.Properties().Lookup(L"RequestArgs");
|
|
514
|
+
// Check if the origin is allowed in conjuction with the withCredentials flag
|
|
515
|
+
// CORS preflight should always exclude credentials although the subsequent CORS request may include credentials.
|
|
516
|
+
ValidateAllowOrigin(controlValues.AllowedOrigin, controlValues.AllowedCredentials, iRequestArgs);
|
|
517
|
+
|
|
518
|
+
// See https://fetch.spec.whatwg.org/#cors-preflight-fetch, section 4.8.7.5
|
|
519
|
+
// Check if the request method is allowed
|
|
520
|
+
bool withCredentials = iRequestArgs.as<RequestArgs>()->WithCredentials;
|
|
521
|
+
bool requestMethodAllowed = false;
|
|
522
|
+
for (const auto &method : controlValues.AllowedMethods) {
|
|
523
|
+
if (L"*" == method) {
|
|
524
|
+
if (!withCredentials) {
|
|
525
|
+
requestMethodAllowed = true;
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
} else if (boost::iequals(method, request.Method().ToString())) {
|
|
529
|
+
requestMethodAllowed = true;
|
|
530
|
+
break;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Preflight should always allow simple CORS methods
|
|
535
|
+
requestMethodAllowed |= s_simpleCorsMethods.find(request.Method().ToString().c_str()) != s_simpleCorsMethods.cend();
|
|
536
|
+
|
|
537
|
+
if (!requestMethodAllowed)
|
|
538
|
+
throw hresult_error{
|
|
539
|
+
E_INVALIDARG,
|
|
540
|
+
L"Method [" + request.Method().ToString() +
|
|
541
|
+
L"] is not allowed by Access-Control-Allow-Methods in preflight response"};
|
|
542
|
+
|
|
543
|
+
// Check if request headers are allowed
|
|
544
|
+
// See https://fetch.spec.whatwg.org/#cors-preflight-fetch, section 4.8.7.6-7
|
|
545
|
+
// Check if the header should be allowed through wildcard, if the request does not have credentials.
|
|
546
|
+
bool requestHeadersAllowed = false;
|
|
547
|
+
if (!withCredentials && controlValues.AllowedHeaders.find(L"*") != controlValues.AllowedHeaders.cend()) {
|
|
548
|
+
// "Authorization" header cannot be allowed through wildcard alone.
|
|
549
|
+
// "Authorization" is the only member of https://fetch.spec.whatwg.org/#cors-non-wildcard-request-header-name.
|
|
550
|
+
if (request.Headers().HasKey(L"Authorization") &&
|
|
551
|
+
controlValues.AllowedHeaders.find(L"Authorization") == controlValues.AllowedHeaders.cend())
|
|
552
|
+
throw hresult_error{
|
|
553
|
+
E_INVALIDARG,
|
|
554
|
+
L"Request header field [Authorization] is not allowed by Access-Control-Allow-Headers in preflight response"};
|
|
555
|
+
|
|
556
|
+
requestHeadersAllowed = true;
|
|
557
|
+
}
|
|
558
|
+
if (!requestHeadersAllowed) {
|
|
559
|
+
// Forbidden headers are excluded from the JavaScript layer.
|
|
560
|
+
// User agents may use these headers internally.
|
|
561
|
+
const set unsafeNotForbidenHeaderNames = CorsUnsafeNotForbiddenRequestHeaderNames(request.Headers());
|
|
562
|
+
for (const auto name : unsafeNotForbidenHeaderNames) {
|
|
563
|
+
if (controlValues.AllowedHeaders.find(name) == controlValues.AllowedHeaders.cend())
|
|
564
|
+
throw hresult_error{
|
|
565
|
+
E_INVALIDARG,
|
|
566
|
+
L"Request header field [" + to_hstring(name) +
|
|
567
|
+
L"] is not allowed by Access-Control-Allow-Headers in preflight response"};
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// #9770 - insert into preflight cache
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// See 10.7.4 of https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
|
|
575
|
+
void OriginPolicyHttpFilter::ValidateResponse(HttpResponseMessage const &response, const OriginPolicy originPolicy)
|
|
576
|
+
const {
|
|
577
|
+
bool removeAllCookies = false;
|
|
578
|
+
if (originPolicy == OriginPolicy::SimpleCrossOriginResourceSharing ||
|
|
579
|
+
originPolicy == OriginPolicy::CrossOriginResourceSharing) {
|
|
580
|
+
auto controlValues = ExtractAccessControlValues(response.Headers());
|
|
581
|
+
auto withCredentials =
|
|
582
|
+
response.RequestMessage().Properties().Lookup(L"RequestArgs").try_as<RequestArgs>()->WithCredentials;
|
|
583
|
+
|
|
584
|
+
if (GetRuntimeOptionBool("Http.StrictOriginCheckSimpleCors") &&
|
|
585
|
+
originPolicy == OriginPolicy::SimpleCrossOriginResourceSharing) {
|
|
586
|
+
bool originAllowed = false;
|
|
587
|
+
for (const auto &header : response.Headers()) {
|
|
588
|
+
if (boost::iequals(header.Key(), L"Access-Control-Allow-Origin")) {
|
|
589
|
+
originAllowed |= L"*" == header.Value() || s_origin == Uri{header.Value()};
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (!originAllowed) {
|
|
594
|
+
throw hresult_error{E_INVALIDARG, L"The server does not support CORS or the origin is not allowed"};
|
|
595
|
+
}
|
|
596
|
+
} else {
|
|
597
|
+
auto iRequestArgs = response.RequestMessage().Properties().Lookup(L"RequestArgs");
|
|
598
|
+
ValidateAllowOrigin(controlValues.AllowedOrigin, controlValues.AllowedCredentials, iRequestArgs);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (originPolicy == OriginPolicy::SimpleCrossOriginResourceSharing) {
|
|
602
|
+
// Filter out response headers that are not in the Simple CORS whitelist
|
|
603
|
+
std::queue<hstring> nonSimpleNames;
|
|
604
|
+
for (const auto &header : response.Headers().GetView()) {
|
|
605
|
+
if (s_simpleCorsResponseHeaderNames.find(header.Key().c_str()) == s_simpleCorsResponseHeaderNames.cend())
|
|
606
|
+
nonSimpleNames.push(header.Key());
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
while (!nonSimpleNames.empty()) {
|
|
610
|
+
response.Headers().Remove(nonSimpleNames.front());
|
|
611
|
+
nonSimpleNames.pop();
|
|
612
|
+
}
|
|
613
|
+
} else {
|
|
614
|
+
// Filter out response headers that are not simple headers and not in expose list
|
|
615
|
+
|
|
616
|
+
// Keep simple headers and those found in the expose header list.
|
|
617
|
+
if (withCredentials || controlValues.ExposedHeaders.find(L"*") == controlValues.ExposedHeaders.cend()) {
|
|
618
|
+
std::queue<hstring> nonSimpleNonExposedHeaders;
|
|
619
|
+
|
|
620
|
+
for (const auto &header : response.Headers().GetView()) {
|
|
621
|
+
if (s_simpleCorsResponseHeaderNames.find(header.Key().c_str()) == s_simpleCorsResponseHeaderNames.cend() &&
|
|
622
|
+
controlValues.ExposedHeaders.find(header.Key().c_str()) == controlValues.ExposedHeaders.cend()) {
|
|
623
|
+
nonSimpleNonExposedHeaders.push(header.Key());
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
while (!nonSimpleNonExposedHeaders.empty()) {
|
|
628
|
+
response.Headers().Remove(nonSimpleNonExposedHeaders.front());
|
|
629
|
+
nonSimpleNonExposedHeaders.pop();
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// When withCredentials is false, request cannot include cookies. Also, cookies will be ignored in responses.
|
|
635
|
+
removeAllCookies = !withCredentials && GetRuntimeOptionBool("Http.RemoveCookiesFromResponse");
|
|
636
|
+
} // originPolicy == SimpleCrossOriginResourceSharing || CrossOriginResourceSharing
|
|
637
|
+
|
|
638
|
+
// Don't expose HttpOnly cookies to JavaScript
|
|
639
|
+
RemoveHttpOnlyCookiesFromResponseHeaders(response, removeAllCookies);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
ResponseOperation OriginPolicyHttpFilter::SendPreflightAsync(HttpRequestMessage const &request) const {
|
|
643
|
+
// TODO: Inject user agent?
|
|
644
|
+
|
|
645
|
+
auto coRequest = request;
|
|
646
|
+
|
|
647
|
+
HttpRequestMessage preflightRequest;
|
|
648
|
+
|
|
649
|
+
// Section 4.8.2 https://fetch.spec.whatwg.org/#cors-preflight-fetch
|
|
650
|
+
preflightRequest.Method(HttpMethod::Options());
|
|
651
|
+
preflightRequest.RequestUri(coRequest.RequestUri());
|
|
652
|
+
preflightRequest.Headers().Insert(L"Accept", L"*/*");
|
|
653
|
+
preflightRequest.Headers().Insert(L"Access-Control-Request-Method", coRequest.Method().ToString());
|
|
654
|
+
|
|
655
|
+
auto headerNames = wstring{};
|
|
656
|
+
auto headerItr = coRequest.Headers().begin();
|
|
657
|
+
if (headerItr != coRequest.Headers().end()) {
|
|
658
|
+
headerNames += (*headerItr).Key();
|
|
659
|
+
|
|
660
|
+
while (++headerItr != coRequest.Headers().end())
|
|
661
|
+
headerNames += L", " + (*headerItr).Key();
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
if (coRequest.Content()) {
|
|
665
|
+
headerItr = coRequest.Content().Headers().begin();
|
|
666
|
+
if (headerItr != coRequest.Content().Headers().end()) {
|
|
667
|
+
headerNames += (*headerItr).Key();
|
|
668
|
+
|
|
669
|
+
while (++headerItr != coRequest.Content().Headers().end())
|
|
670
|
+
headerNames += L", " + (*headerItr).Key();
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
preflightRequest.Headers().Insert(L"Access-Control-Request-Headers", headerNames);
|
|
675
|
+
preflightRequest.Headers().Insert(L"Origin", s_origin.AbsoluteCanonicalUri());
|
|
676
|
+
preflightRequest.Headers().Insert(L"Sec-Fetch-Mode", L"CORS");
|
|
677
|
+
|
|
678
|
+
co_return {co_await m_innerFilter.SendRequestAsync(preflightRequest)};
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
#pragma region IHttpFilter
|
|
682
|
+
|
|
683
|
+
ResponseOperation OriginPolicyHttpFilter::SendRequestAsync(HttpRequestMessage const &request) {
|
|
684
|
+
auto coRequest = request;
|
|
685
|
+
|
|
686
|
+
// Set initial origin policy to global runtime option.
|
|
687
|
+
request.Properties().Insert(L"OriginPolicy", winrt::box_value(GetRuntimeOptionInt("Http.OriginPolicy")));
|
|
688
|
+
|
|
689
|
+
// Allow only HTTP or HTTPS schemes
|
|
690
|
+
if (GetRuntimeOptionBool("Http.StrictScheme") && coRequest.RequestUri().SchemeName() != L"https" &&
|
|
691
|
+
coRequest.RequestUri().SchemeName() != L"http")
|
|
692
|
+
throw hresult_error{E_INVALIDARG, L"Invalid URL scheme: [" + s_origin.SchemeName() + L"]"};
|
|
693
|
+
|
|
694
|
+
if (!GetRuntimeOptionBool("Http.OmitCredentials")) {
|
|
695
|
+
coRequest.Properties().Lookup(L"RequestArgs").as<RequestArgs>()->WithCredentials = false;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Ensure absolute URL
|
|
699
|
+
coRequest.RequestUri(Uri{coRequest.RequestUri().AbsoluteCanonicalUri()});
|
|
700
|
+
|
|
701
|
+
auto originPolicy = ValidateRequest(coRequest);
|
|
702
|
+
if (originPolicy == OriginPolicy::SimpleCrossOriginResourceSharing ||
|
|
703
|
+
originPolicy == OriginPolicy::CrossOriginResourceSharing) {
|
|
704
|
+
if (coRequest.RequestUri().UserName().size() > 0 || coRequest.RequestUri().Password().size() > 0) {
|
|
705
|
+
coRequest.RequestUri(Uri{coRequest.RequestUri().DisplayUri()});
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
try {
|
|
710
|
+
// #9770 - Validate preflight cache
|
|
711
|
+
if (originPolicy == OriginPolicy::CrossOriginResourceSharing) {
|
|
712
|
+
// If inner filter can AllowRedirect, disable for preflight.
|
|
713
|
+
winrt::impl::com_ref<IHttpBaseProtocolFilter> baseFilter;
|
|
714
|
+
if (baseFilter = m_innerFilter.try_as<IHttpBaseProtocolFilter>()) {
|
|
715
|
+
baseFilter.AllowAutoRedirect(false);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
auto preflightResponse = co_await SendPreflightAsync(coRequest);
|
|
719
|
+
|
|
720
|
+
if (baseFilter) {
|
|
721
|
+
baseFilter.AllowAutoRedirect(true);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
ValidatePreflightResponse(coRequest, preflightResponse);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
auto response = co_await m_innerFilter.SendRequestAsync(coRequest);
|
|
728
|
+
|
|
729
|
+
ValidateResponse(response, originPolicy);
|
|
730
|
+
|
|
731
|
+
co_return response;
|
|
732
|
+
|
|
733
|
+
} catch (hresult_error const &e) {
|
|
734
|
+
throw e;
|
|
735
|
+
} catch (const std::exception &e) {
|
|
736
|
+
throw hresult_error{E_FAIL, to_hstring(e.what())};
|
|
737
|
+
} catch (...) {
|
|
738
|
+
throw hresult_error{E_FAIL, L"Unspecified error processing Origin Policy request"};
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
#pragma endregion IHttpFilter
|
|
743
|
+
|
|
744
|
+
#pragma endregion OriginPolicyHttpFilter
|
|
745
|
+
|
|
746
|
+
} // namespace Microsoft::React::Networking
|