packages feed

http-interchange 0.3.2.1 → 0.3.2.2

raw patch · 5 files changed

+156/−6 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for http-interchange +## 0.3.2.2 -- 2024-08-23++* Allow all RFC 7230 tchar in header name+ ## 0.3.2.1 -- 2024-02-07  * List test suite file dependencies in `extra-source-files` so that Hackage
+ golden/response/003.input view
@@ -0,0 +1,19 @@+HTTP/1.1 200 OK
+Content-Length: 0
+Access-Control-Allow-Origin: *
+Access-Control-Allow-Credentials: true
+Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, SCRIPT
+Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, SCRIPT
+Access-Control-Allow-Headers: Authorization,Content-Type,Content-Encoding,Accept,X-Netflix.application.name,X-Netflix.application.version,X-Netflix.esn,X-Netflix.device.type,X-Netflix.certification.version,X-Netflix.request.uuid,X-Netflix.originating.request.uuid,X-Netflix.user.id,X-Netflix.oauth.consumer.key,X-Netflix.oauth.token,X-Netflix.ichnaea.request.type,X-Netflix.Request.Routing,X-NETFLIX-PREAPP-PARTNER-ID,X-NETFLIX-PREAPP-INTEGRITY-VALUE,X-Netflix.Request.Priority,X-Netflix.Retry.Client.Policy,X-Netflix.Client.Request.Name,X-Netflix.Request.Retry.Policy,X-Netflix.Request.Retry.Policy.Default,X-Netflix.request.client.user.guid,X-Netflix.Request.NonJson.Headers,X-Netflix.esnPrefix,X-Netflix.browserName,X-Netflix.browserVersion,X-Netflix.osName,X-Netflix.osVersion,X-Netflix.uiVersion,X-Netflix.clientType,X-NETFLIX-PERSONALIZATION-ID,X-NETFLIX-DET-TOKEN,X-NETFLIX-DET-PARTNER-PAI,X-NETFLIX-RESPONSE-OVERRIDDEN,X-NETFLIX-DET-DEPRECATION,X-Netflix.context.locales,X-Netflix.context.ui-flavor,X-Netflix.context.ale.token,X-Netflix.context.app-version,X-Netflix.context.schema-variant,X-Netflix.Request.toplevel.uuid,f9hi42t,x-session,X-Netflix.Request.Attempt
+Access-Control-Expose-Headers: X-Netflix.Retry.Server.Policy,X-Netflix.Response.Tag,X-Netflix.Geo.Info,X-Netflix.request.inbound.identity.changed,Via,X-Netflix.Retry.Server.Policy.retryAfterSeconds,X-Netflix.Retry.Server.Policy.maxRetries,X-Ftl-Error,X-Netflix.uiVersion,X-Netflix.Playapi.Backoff
+Via: 1.1 i-08d45052140120818 (us-east-2)
+X-Xss-Protection: 1; mode=block; report=https://www.netflix.com/ichnaea/log/freeform/xssreport
+X-Content-Type-Options: nosniff
+Strict-Transport-Security: max-age=31536000; includeSubDomains
+X-Originating-URL: http://www.netflix.com/
+Set-Cookie: nfvdid=BQFmAAEBEFU_lDUnKbaHRi5tl0Mhqc5ALJIuWadL1PlbBLQGl0n-1n-GCB41ux6moG0JMBj22dNaLsaXeB3DmLHrc6SUwOP43peCxZ-9EQNtFxz7gqTC0w%3D%3D; Domain=.netflix.com; Path=/; Max-Age=31536000
+Set-Cookie: SecureNetflixId=v%3D3%26mac%3DAQEAEQABABRXxJiCXjMlnNAESuzV2TyKuP3eS3p8YJc.%26dt%3D1724424807026; Domain=.netflix.com; Expires=Sat, 23 Aug 2025 14:53:27 GMT; Path=/; HttpOnly; Secure; SameSite=Strict
+Set-Cookie: NetflixId=v%3D3%26ct%3DBgjHlOvcAxK_AQ-lxAypPWxfZpzrloHvpi11GUHAmWl-qgv5VMtuoq9QRvkhHh1zrdLY_ALqrfLQh6YFvx1vjTj6Bwwaxa3_5dZMTkdMBJ9jBUR2nqz-uANNz8MLx210xS7_tyfEk8bTLNGPLXfUnE-XsqKT-Lt5x6A9VZzCrjsHtWOPObAA8ast0yC-FfMJT-1cxBnBDBd9LQeFysgRrRi3VjA6bb-KXqABXABbuXKS0iY1e8wgqs_hv4cvHBciaFkIuDO1GH4vGAYiDgoMorBJMaCVqFf0KRMy; Domain=.netflix.com; Expires=Sat, 23 Aug 2025 14:53:27 GMT; Path=/; HttpOnly; Secure; SameSite=Lax
+X-Netflix.nfstatus: 1_1
+X-Netflix.proxy.execution-time: 61
+
+ golden/response/003.output view
@@ -0,0 +1,59 @@+Response+  { statusLine =+      StatusLine { statusCode = 200 , statusReason = "OK" }+  , headers =+      [ Header { name = "Content-Length" , value = "0" }+      , Header { name = "Access-Control-Allow-Origin" , value = "*" }+      , Header+          { name = "Access-Control-Allow-Credentials" , value = "true" }+      , Header+          { name = "Allow"+          , value = "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, SCRIPT"+          }+      , Header+          { name = "Access-Control-Allow-Methods"+          , value = "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, SCRIPT"+          }+      , Header+          { name = "Access-Control-Allow-Headers"+          , value =+              "Authorization,Content-Type,Content-Encoding,Accept,X-Netflix.application.name,X-Netflix.application.version,X-Netflix.esn,X-Netflix.device.type,X-Netflix.certification.version,X-Netflix.request.uuid,X-Netflix.originating.request.uuid,X-Netflix.user.id,X-Netflix.oauth.consumer.key,X-Netflix.oauth.token,X-Netflix.ichnaea.request.type,X-Netflix.Request.Routing,X-NETFLIX-PREAPP-PARTNER-ID,X-NETFLIX-PREAPP-INTEGRITY-VALUE,X-Netflix.Request.Priority,X-Netflix.Retry.Client.Policy,X-Netflix.Client.Request.Name,X-Netflix.Request.Retry.Policy,X-Netflix.Request.Retry.Policy.Default,X-Netflix.request.client.user.guid,X-Netflix.Request.NonJson.Headers,X-Netflix.esnPrefix,X-Netflix.browserName,X-Netflix.browserVersion,X-Netflix.osName,X-Netflix.osVersion,X-Netflix.uiVersion,X-Netflix.clientType,X-NETFLIX-PERSONALIZATION-ID,X-NETFLIX-DET-TOKEN,X-NETFLIX-DET-PARTNER-PAI,X-NETFLIX-RESPONSE-OVERRIDDEN,X-NETFLIX-DET-DEPRECATION,X-Netflix.context.locales,X-Netflix.context.ui-flavor,X-Netflix.context.ale.token,X-Netflix.context.app-version,X-Netflix.context.schema-variant,X-Netflix.Request.toplevel.uuid,f9hi42t,x-session,X-Netflix.Request.Attempt"+          }+      , Header+          { name = "Access-Control-Expose-Headers"+          , value =+              "X-Netflix.Retry.Server.Policy,X-Netflix.Response.Tag,X-Netflix.Geo.Info,X-Netflix.request.inbound.identity.changed,Via,X-Netflix.Retry.Server.Policy.retryAfterSeconds,X-Netflix.Retry.Server.Policy.maxRetries,X-Ftl-Error,X-Netflix.uiVersion,X-Netflix.Playapi.Backoff"+          }+      , Header+          { name = "Via" , value = "1.1 i-08d45052140120818 (us-east-2)" }+      , Header+          { name = "X-Xss-Protection"+          , value =+              "1; mode=block; report=https://www.netflix.com/ichnaea/log/freeform/xssreport"+          }+      , Header { name = "X-Content-Type-Options" , value = "nosniff" }+      , Header+          { name = "Strict-Transport-Security"+          , value = "max-age=31536000; includeSubDomains"+          }+      , Header+          { name = "X-Originating-URL" , value = "http://www.netflix.com/" }+      , Header+          { name = "Set-Cookie"+          , value =+              "nfvdid=BQFmAAEBEFU_lDUnKbaHRi5tl0Mhqc5ALJIuWadL1PlbBLQGl0n-1n-GCB41ux6moG0JMBj22dNaLsaXeB3DmLHrc6SUwOP43peCxZ-9EQNtFxz7gqTC0w%3D%3D; Domain=.netflix.com; Path=/; Max-Age=31536000"+          }+      , Header+          { name = "Set-Cookie"+          , value =+              "SecureNetflixId=v%3D3%26mac%3DAQEAEQABABRXxJiCXjMlnNAESuzV2TyKuP3eS3p8YJc.%26dt%3D1724424807026; Domain=.netflix.com; Expires=Sat, 23 Aug 2025 14:53:27 GMT; Path=/; HttpOnly; Secure; SameSite=Strict"+          }+      , Header+          { name = "Set-Cookie"+          , value =+              "NetflixId=v%3D3%26ct%3DBgjHlOvcAxK_AQ-lxAypPWxfZpzrloHvpi11GUHAmWl-qgv5VMtuoq9QRvkhHh1zrdLY_ALqrfLQh6YFvx1vjTj6Bwwaxa3_5dZMTkdMBJ9jBUR2nqz-uANNz8MLx210xS7_tyfEk8bTLNGPLXfUnE-XsqKT-Lt5x6A9VZzCrjsHtWOPObAA8ast0yC-FfMJT-1cxBnBDBd9LQeFysgRrRi3VjA6bb-KXqABXABbuXKS0iY1e8wgqs_hv4cvHBciaFkIuDO1GH4vGAYiDgoMorBJMaCVqFf0KRMy; Domain=.netflix.com; Expires=Sat, 23 Aug 2025 14:53:27 GMT; Path=/; HttpOnly; Secure; SameSite=Lax"+          }+      , Header { name = "X-Netflix.nfstatus" , value = "1_1" }+      , Header { name = "X-Netflix.proxy.execution-time" , value = "61" }+      ]+  }
http-interchange.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               http-interchange-version:            0.3.2.1+version:            0.3.2.2 license:            BSD-3-Clause license-file:       LICENSE author:             Andrew Martin
src/Http/Header.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PatternSynonyms #-}  module Http.Header   ( Header (..)@@ -15,6 +16,7 @@ import Data.Bytes.Types (Bytes (Bytes)) import Data.Primitive (ByteArray (ByteArray), SmallArray, SmallMutableArray) import Data.Text (Text)+import Data.Word (Word8)  import Data.Bytes qualified as Bytes import Data.Bytes.Builder qualified as Builder@@ -74,9 +76,62 @@           parserHeaderStep (ix + 1) (n - 1) dst         else Parser.fail () +pattern Bang :: Word8+pattern Bang = 0x21++pattern Pound :: Word8+pattern Pound = 0x23++pattern Dollar :: Word8+pattern Dollar = 0x24++pattern Percent :: Word8+pattern Percent = 0x25++pattern Ampersand :: Word8+pattern Ampersand = 0x26++pattern SingleQuote :: Word8+pattern SingleQuote = 0x27++pattern Asterisk :: Word8+pattern Asterisk = 0x2A++pattern Plus :: Word8+pattern Plus = 0x2B++pattern Hyphen :: Word8+pattern Hyphen = 0x2D++pattern Period :: Word8+pattern Period = 0x2E++pattern Caret :: Word8+pattern Caret = 0x5E++pattern Underscore :: Word8+pattern Underscore = 0x5F++pattern Backtick :: Word8+pattern Backtick = 0x60++pattern Pipe :: Word8+pattern Pipe = 0x7C++pattern Twiddle :: Word8+pattern Twiddle = 0x7E++pattern HorizontalTab :: Word8+pattern HorizontalTab = 0x09+ {- | Parse a single HTTP header including the trailing CRLF sequence. From RFC 7230: +> token          = 1*tchar+> tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"+>                / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" +>                / DIGIT / ALPHA+>  > header-field   = field-name ":" OWS field-value OWS > field-name     = token > field-value    = *( field-content / obs-fold )@@ -85,19 +140,32 @@ -} parser :: Parser () s Header parser = do-  -- Header name may contain: a-z, A-Z, 0-9, underscore, hyphen+  -- Header name may contain: a-z, A-Z, 0-9, several different symbols   !name <- Parser.takeWhile $ \c ->     (c >= 0x41 && c <= 0x5A)       || (c >= 0x61 && c <= 0x7A)       || (c >= 0x30 && c <= 0x39)-      || c == 0x2D-      || c == 0x5F+      || c == Bang+      || c == Pound+      || c == Dollar+      || c == Percent+      || c == Ampersand+      || c == SingleQuote+      || c == Asterisk+      || c == Plus+      || c == Hyphen+      || c == Period+      || c == Caret+      || c == Underscore+      || c == Backtick+      || c == Pipe+      || c == Twiddle   Latin.char () ':'   Latin.skipWhile (\c -> c == ' ' || c == '\t')-  -- Header name allows vchar, space, and tab.+  -- Header value allows vchar, space, and tab.   value0 <- Parser.takeWhile $ \c ->     (c >= 0x20 && c <= 0x7e)-      || (c == 0x09)+      || (c == HorizontalTab)   Latin.char2 () '\r' '\n'   -- We only need to trim the end because the leading spaces and tab   -- were already skipped.