HTTP2 push and native ES modules: "entry" module push is ignored - http2

I’ve been experimenting with approaches to serving native ES modules over HTTP2. Pretty much everything works great (where supported), but there’s a quirk that I can’t make much sense of.
Given a request for the / document, I push the resources which directly or indirectly are known to be dependencies of that document. In this case that ends up being three additional resources that piggyback via pushes:
/index.css (a dependency via <link href ...>)
/index.js (a dependency via <script type="module" src ...>
/routes.js (an indirect dependency, imported by index.js)
All three resources appear to push successfully from the server side. However, Chrome makes a second request for "/index.js" despite the push with the first request. Neither of the other two resources are requested; those pushed responses appear to be acknowledged correctly.
At first I thought this was a Chrome quirk, just a rough edge on a newly minted feature. But the same behavior is demonstrated in Firefox when the module support flag is enabled, which made me wonder if this is deliberate for some reason.
Logging from backend corresponding to above requests:
RECEIVED REQUEST: GET /
...PUSHING /index.css
...PUSHING /index.js
...PUSHING /routes.js
RECEIVED REQUEST: GET /index.js
...PUSHING /routes.js
Following up on the instructions from #sbordet: here are transcripts from both requests (great to know this stuff can be introspected in Chrome!):
First Req (/)
3067: HTTP2_SESSION
death.tips:443 (DIRECT)
Start Time: 2017-10-09 10:49:24.597
t=304289 [st= 0] +HTTP2_SESSION [dt=?]
--> host = "death.tips:443"
--> proxy = "DIRECT"
t=304289 [st= 0] HTTP2_SESSION_INITIALIZED
--> protocol = "h2"
--> source_dependency = 3064 (SOCKET)
t=304289 [st= 0] HTTP2_SESSION_SEND_SETTINGS
--> settings = ["[id:1 (SETTINGS_HEADER_TABLE_SIZE) value:65536]","[id:3 (SETTINGS_MAX_CONCURRENT_STREAMS) value:1000]","[id:4 (SETTINGS_INITIAL_WINDOW_SIZE) value:6291456]"]
t=304289 [st= 0] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = 15663105
--> window_size = 15728640
t=304289 [st= 0] HTTP2_SESSION_SEND_WINDOW_UPDATE
--> delta = 15663105
--> stream_id = 0
t=304289 [st= 0] HTTP2_SESSION_SEND_HEADERS
--> exclusive = true
--> fin = true
--> has_priority = true
--> :method: GET
:authority: death.tips
:scheme: https
:path: /
pragma: no-cache
cache-control: no-cache
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3236.0 Safari/537.36
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
--> parent_stream_id = 0
--> source_dependency = 3060 (HTTP_STREAM_JOB)
--> stream_id = 1
--> weight = 256
t=304310 [st=21] HTTP2_SESSION_RECV_SETTINGS
t=304310 [st=21] HTTP2_SESSION_SEND_SETTINGS_ACK
t=304313 [st=24] HTTP2_SESSION_RECV_SETTINGS_ACK
t=304336 [st=47] HTTP2_SESSION_RECV_PUSH_PROMISE
--> :scheme: https
:authority: death.tips
:path: /index.css
:method: GET
--> id = 1
--> promised_stream_id = 2
t=304336 [st=47] HTTP2_STREAM_SEND_PRIORITY
--> exclusive = true
--> parent_stream_id = 1
--> stream_id = 2
--> weight = 110
t=304336 [st=47] HTTP2_SESSION_RECV_PUSH_PROMISE
--> :scheme: https
:authority: death.tips
:path: /index.js
:method: GET
--> id = 1
--> promised_stream_id = 4
t=304336 [st=47] HTTP2_STREAM_SEND_PRIORITY
--> exclusive = true
--> parent_stream_id = 2
--> stream_id = 4
--> weight = 110
t=304336 [st=47] HTTP2_SESSION_RECV_PUSH_PROMISE
--> :scheme: https
:authority: death.tips
:path: /routes.js
:method: GET
--> id = 1
--> promised_stream_id = 6
t=304336 [st=47] HTTP2_STREAM_SEND_PRIORITY
--> exclusive = true
--> parent_stream_id = 4
--> stream_id = 6
--> weight = 110
t=304336 [st=47] HTTP2_SESSION_RECV_HEADERS
--> fin = false
--> :status: 200
cache-control: public, max-age=0
content-encoding: deflate
content-length: 388
content-type: text/html; charset=utf-8
date: Mon, 09 Oct 2017 14:49:24 GMT
etag: "c3QDLn1lTsAqsErFvMgM3bEsUsY="
last-modified: Mon, 09 Oct 2017 14:43:24 GMT
--> stream_id = 1
t=304336 [st=47] HTTP2_SESSION_RECV_HEADERS
--> fin = false
--> :status: 200
cache-control: public, max-age=0
content-encoding: deflate
content-length: 88
content-type: text/css
date: Mon, 09 Oct 2017 14:49:24 GMT
etag: "/qkigeCvJgEE+0+5YhHLgByhKL0="
last-modified: Mon, 09 Oct 2017 14:43:24 GMT
--> stream_id = 2
t=304336 [st=47] HTTP2_SESSION_RECV_HEADERS
--> fin = false
--> :status: 200
cache-control: public, max-age=0
content-encoding: deflate
content-length: 60
content-type: text/javascript
date: Mon, 09 Oct 2017 14:49:24 GMT
etag: "/+cUWoFWkafsB6vSI5wBuB7v4Tk="
last-modified: Mon, 09 Oct 2017 14:43:24 GMT
--> stream_id = 4
t=304336 [st=47] HTTP2_SESSION_RECV_HEADERS
--> fin = false
--> :status: 200
cache-control: public, max-age=0
content-encoding: deflate
content-length: 64
content-type: text/javascript
date: Mon, 09 Oct 2017 14:49:24 GMT
etag: "2ZM3pEXqn9z1d5tkBr2x5kdHsGk="
last-modified: Mon, 09 Oct 2017 14:43:24 GMT
--> stream_id = 6
t=304336 [st=47] HTTP2_SESSION_RECV_DATA
--> fin = false
--> size = 388
--> stream_id = 1
t=304336 [st=47] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = -388
--> window_size = 15728252
t=304336 [st=47] HTTP2_SESSION_RECV_DATA
--> fin = true
--> size = 0
--> stream_id = 1
t=304336 [st=47] HTTP2_SESSION_RECV_DATA
--> fin = false
--> size = 88
--> stream_id = 2
t=304336 [st=47] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = -88
--> window_size = 15728164
t=304336 [st=47] HTTP2_SESSION_RECV_DATA
--> fin = true
--> size = 0
--> stream_id = 2
t=304336 [st=47] HTTP2_SESSION_RECV_DATA
--> fin = false
--> size = 60
--> stream_id = 4
t=304336 [st=47] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = -60
--> window_size = 15728104
t=304336 [st=47] HTTP2_SESSION_RECV_DATA
--> fin = true
--> size = 0
--> stream_id = 4
t=304336 [st=47] HTTP2_SESSION_RECV_DATA
--> fin = false
--> size = 64
--> stream_id = 6
t=304336 [st=47] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = -64
--> window_size = 15728040
t=304336 [st=47] HTTP2_SESSION_RECV_DATA
--> fin = true
--> size = 0
--> stream_id = 6
t=304337 [st=48] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = 388
--> window_size = 15728428
t=304342 [st=53] HTTP2_STREAM_ADOPTED_PUSH_STREAM
--> stream_id = 2
--> url = "https://death.tips/index.css"
t=304343 [st=54] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = 88
--> window_size = 15728516
Second Req (/index.js)
3085: HTTP2_SESSION
death.tips:443 (DIRECT)
Start Time: 2017-10-09 10:49:24.694
t=304386 [st= 0] +HTTP2_SESSION [dt=?]
--> host = "death.tips:443"
--> proxy = "DIRECT"
t=304386 [st= 0] HTTP2_SESSION_INITIALIZED
--> protocol = "h2"
--> source_dependency = 3084 (SOCKET)
t=304386 [st= 0] HTTP2_SESSION_SEND_SETTINGS
--> settings = ["[id:1 (SETTINGS_HEADER_TABLE_SIZE) value:65536]","[id:3 (SETTINGS_MAX_CONCURRENT_STREAMS) value:1000]","[id:4 (SETTINGS_INITIAL_WINDOW_SIZE) value:6291456]"]
t=304386 [st= 0] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = 15663105
--> window_size = 15728640
t=304386 [st= 0] HTTP2_SESSION_SEND_WINDOW_UPDATE
--> delta = 15663105
--> stream_id = 0
t=304386 [st= 0] HTTP2_SESSION_SEND_HEADERS
--> exclusive = true
--> fin = true
--> has_priority = true
--> :method: GET
:authority: death.tips
:scheme: https
:path: /index.js
pragma: no-cache
cache-control: no-cache
origin: https://death.tips
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3236.0 Safari/537.36
accept: */*
referer: https://death.tips/
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
--> parent_stream_id = 0
--> source_dependency = 3080 (HTTP_STREAM_JOB)
--> stream_id = 1
--> weight = 220
t=304405 [st=19] HTTP2_SESSION_RECV_SETTINGS
t=304405 [st=19] HTTP2_SESSION_SEND_SETTINGS_ACK
t=304409 [st=23] HTTP2_SESSION_RECV_SETTINGS_ACK
t=304409 [st=23] HTTP2_SESSION_RECV_PUSH_PROMISE
--> :scheme: https
:authority: death.tips
:path: /routes.js
:method: GET
--> id = 1
--> promised_stream_id = 2
t=304409 [st=23] HTTP2_STREAM_SEND_PRIORITY
--> exclusive = true
--> parent_stream_id = 1
--> stream_id = 2
--> weight = 110
t=304409 [st=23] HTTP2_SESSION_RECV_HEADERS
--> fin = false
--> :status: 200
cache-control: public, max-age=0
content-encoding: deflate
content-length: 60
content-type: text/javascript
date: Mon, 09 Oct 2017 14:49:24 GMT
etag: "/+cUWoFWkafsB6vSI5wBuB7v4Tk="
last-modified: Mon, 09 Oct 2017 14:43:24 GMT
--> stream_id = 1
t=304409 [st=23] HTTP2_SESSION_RECV_HEADERS
--> fin = false
--> :status: 200
cache-control: public, max-age=0
content-encoding: deflate
content-length: 64
content-type: text/javascript
date: Mon, 09 Oct 2017 14:49:24 GMT
etag: "2ZM3pEXqn9z1d5tkBr2x5kdHsGk="
last-modified: Mon, 09 Oct 2017 14:43:24 GMT
--> stream_id = 2
t=304409 [st=23] HTTP2_SESSION_RECV_DATA
--> fin = false
--> size = 60
--> stream_id = 1
t=304409 [st=23] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = -60
--> window_size = 15728580
t=304409 [st=23] HTTP2_SESSION_RECV_DATA
--> fin = true
--> size = 0
--> stream_id = 1
t=304409 [st=23] HTTP2_SESSION_RECV_DATA
--> fin = false
--> size = 64
--> stream_id = 2
t=304409 [st=23] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = -64
--> window_size = 15728516
t=304409 [st=23] HTTP2_SESSION_RECV_DATA
--> fin = true
--> size = 0
--> stream_id = 2
t=304410 [st=24] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = 60
--> window_size = 15728576
t=304412 [st=26] HTTP2_STREAM_ADOPTED_PUSH_STREAM
--> stream_id = 2
--> url = "https://death.tips/routes.js"
t=304413 [st=27] HTTP2_SESSION_UPDATE_RECV_WINDOW
--> delta = 64
--> window_size = 15728640

This was quite a mystery!
The issue is that — well, I’m not gonna be able to explain this well, but my shallow understanding is that documents are requested "with credentials", but <script type="module"> triggers, by default, a "no credentials" request. The push promise for the script is "with credentials" by association, but never the twain shall meet. So the browser must make a new request because the push promise "doesn’t count". And there is a solution:
<script type="module" src="/index.js" crossorigin="use-credentials">
I would never have thought to use a "crossorigin" attribute to fetch a resource on the same site, but there it is. Push gets adopted, and my little experiment just got twice as fast.
Here’s the transcript of the whole conversation in #whatwg:
[7:35pm] <bathos> I’ve got a question about interactions between module
loading and HTTP2 that’s had me scratching my head for a few days — is
that something appropriate to ask about here?
[7:37pm] <jyasskin> bathos: Yes.
[7:39pm] <bathos> Cool. I’ve been experimenting with serving resources using
HTTP2 push — assemble a dep graph in advance and follow through on
requests by provisioning their known dependencies as push promises. This
works great on the whole, but there’s a quirk I’ve observed that seems to
be related specifically to ES module "entrypoints".
[7:40pm] <bathos> I asked about it on SO, so there’s a bit of detail in the
question and comments there: https://stackoverflow.com/questions/46642569/http2-push-and-native-es-modules-entry-module-push-is-ignored
[7:40pm] <bathos> The gist though:
[7:41pm] <bathos> Given a request for a document which contains
<script type="module" src="something">, and an http2 session which
includes a push promise for "something", the "something" push is never
adopted. Instead, the browser makes a fresh request for it.
[7:41pm] <jyasskin> Domenic: ^
[7:42pm] <bathos> Dependencies imported _in_ ES are adopted.
[7:42pm] <jyasskin> bathos: I'm not an expert here, but your question
reminds me of the with-vs-no-credentials problem in
https://github.com/whatwg/fetch/issues/354.
[7:42pm] <bathos> And if I reference the same module in a different way in
the root document, e.g. a preload <link>, it is successfully adopted. It’s
peculiar to type="module"
[7:43pm] <bathos> oh, interesting
[7:43pm] <jyasskin> Apologies if I've just sent you on a wild goose chase.
[7:44pm] <bathos> I have been on a lot for the last two days haha! Since
HTTP2 is still pretty mysterious to me, it’d been hard to rule out the
possibility that I’m doing something weird there, though I’m pretty sure
at this point that I’m not.
[7:52pm] <bathos> jyasskin you genius!
[7:53pm] <jyasskin> s/genius/pattern-matcher/ :)
[7:53pm] <bathos> crossorigin="use-credentials" in the doc actually makes
the module push promise get adopted
[7:54pm] <bathos> I never would have thought to try "crossorigin" on a file
on the same host haha

The browser activity is the following:
send request (stream=1)
receive push promise for /index.css (stream=2)
receive push promise for /index.js (stream=4)
receive push promise for /routes.js (stream=6)
receive headers for stream=1
receive headers for stream=2
receive headers for stream=4
receive headers for stream=6
receive data for stream=1 (388+0 bytes)
receive data for stream=2 (88+0 bytes)
receive data for stream=4 (60+0 bytes)
receive data for stream=6 (64+0 bytes)
My interpretation is that the browser receives the whole body for the primary request (stream=1) before it receives the whole body for the pushed resources.
I'm guess internally the browser starts parsing the HTML, figure out it needs /index.js, find that it is not yet arrived although it has been promised, and therefore it issues a request for it.
The browser probably needs /index.css later than it needs /index.js, and by the time it needs the CSS it has already arrived to the browser as a pushed resource, and that would explain why /index.css is used from the push cache.
If you can control when the resources are written to the network, try to send the whole body of /index.js before sending the HTML body. That should make the browser aware that index.js is fully available in the push cache and use it from there, rather than requesting it anew.
A final note that the push cache implementation in Chrome has varied greatly over the years/months, so what could be true today may not hold in the future.

Related

Oracle UTL_HTTP request returns a shorter response than when the same request is done in Python or curl

I'm accessing a REST service for data query and download. This is the very first call that performs the authentication. The response is a json structure that contains an authentication token.
When I do this call with curl ...
$ curl -v -X POST ${AUTH_URL} \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'apikey='${API_KEY}'&grant_type=api_key&client_id=IDP'
... I get the following response.
First the headers:
< server: IIS
< date: Thu, 25 Feb 2021 17:59:34 GMT
< content-type: application/json
< content-length: 1500
< x-content-type-options: nosniff
< x-xss-protection: 1; mode=block
< strict-transport-security: max-age=31536000; includeSubdomains;
< cache-control: no-store
< set-cookie: KC_RESTART=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0; Path=/auth/realms/IDP/; HttpOnly
< pragma: no-cache
< x-frame-options: SAMEORIGIN
< referrer-policy: no-referrer
< vary: Origin
< via: 1.1 google
< alt-svc: clear
And the content:
{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxMThSRENzZTlqUWR4UVRnSkt2ZXlvSHBaaWE4R0pIVEU5RjJPSmE1M3N3In0.eyJleHAiOjE2MTQyOTAzNzQsImlhdCI6MTYxNDI3NTk3NCwianRpIjoiNzBkMmMwZGMtZWY3Yy00NDM5LWJiNmUtNmQ4MDEzZGU2YTU0IiwiaXNzIjoiaHR0cHM6Ly9hdXRoZW50aWNhdGUuZm91bmRhdGlvbi5hcGkub25lYXRsYXMuYWlyYnVzLmNvbS9hdXRoL3JlYWxtcy9JRFAiLCJhdWQiOiJJRFAiLCJzdWIiOiJmNmI0ZjVkNC0zMzZiLTRlMTctODc3Ni1jNjA1ZTczNTRjYmIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJJRFAiLCJzZXNzaW9uX3N0YXRlIjoiODJkYWM4MjMtMTViOS00MmVlLWE2YzEtZjg2ZDQ2MzY1ZjAzIiwiYWNyIjoiMSIsInNjb3BlIjoiIiwibmJmIjowLCJyb2xlIjoie1wiZ2VvLmlkcC5ub3RpZnlcIjpbXCJ1c2VyXCJdLFwiZ2VvLmFwcC5vYWRcIjpbXCJ1c2VyXCJdLFwiZ2VvLmlkcC5kYXRhc3RvcmVcIjpbXCJ1c2VyXCJdLFwiZ2VvLmFwcC53b3JrYmVuY2hcIjpbXCJ1c2VyXCJdfSIsInJvbGVzIjp7Imdlby5pZHAubm90aWZ5IjpbInVzZXIiXSwiZ2VvLmFwcC5vYWQiOlsidXNlciJdLCJnZW8uaWRwLmRhdGFzdG9yZSI6WyJ1c2VyIl0sImdlby5hcHAud29ya2JlbmNoIjpbInVzZXIiXX0sInN1aWQiOiIxMTg2NTEzNTQ2IiwidXVpZCI6Ijc5Yjg0MTZlLTY0NDYtNGMwYy1hODg1LWY1MzE2ZGMzOWMyZSIsImxvYSI6MTAwfQ.5W_E4fkhirbJZNAJ_TwMbLhcKdmnHBXOjvLUr4vW-DBRvSFfQrpdlDHLMIVI4B7bZ-OU_FVnH__i_diKYJFRH4l3Zqy8maa1pyj_WhZJksqBB69ehv8xx_3qtuJCZ0z0hln0FzmyG_Ep_uaru3gK_h33SuFxjdKr4F5XocyrYpGE-ewm-mBLj4DOBnZSJ4HgV0BG02LJIPIU8BybTmvgV-4mW3LXOVKDUJMmP4TF_ZEUzNz4a1vhoW4VIOvaNkk_8v8m_R4zjNOGmd_4jWEywORBZ1ofqvn72usY7TWEVpGBxR-rKYgzWXrdeBE4_l61MT420rBID9dbI2zRgEyVIQ","expires_in":14400,"refresh_expires_in":0,"token_type":"bearer","not-before-policy":0,"session_state":"82dac823-15b9-42ee-a6c1-f86d46365f03","scope":""}
Notice that the length of the content is 1500. That is also what the content-length: 1500 header says. When I do the same test using Python, I get the same result: a 1500 characters result.
But when I do the same test using Oracle UTL_HTTP, the result is only 1453 characters. Here is debugging from my PL/SQL code:
% resp.status_code=200
% resp.reason_phrase=OK
% resp.http_version=HTTP/1.0
% resp.get_headers
% .. Server: IIS
% .. Date: Thu, 25 Feb 2021 17:50:51 GMT
% .. Content-Type: application/json
% .. Content-Length: 1453
% .. X-Content-Type-Options: nosniff
% .. X-XSS-Protection: 1; mode=block
% .. Strict-Transport-Security: max-age=31536000; includeSubdomains;
% .. Cache-Control: no-store
% .. Set-Cookie: KC_RESTART=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT;
Max-Age=0; Path=/auth/realms/IDP/; HttpOnly
% .. Pragma: no-cache
% .. X-Frame-Options: SAMEORIGIN
% .. Referrer-Policy: no-referrer
% .. Vary: Origin
% .. Via: 1.1 google
% .. Alt-Svc: clear
% Response:
{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxMThSRENzZT
lqUWR4UVRnSkt2ZXlvSHBaaWE4R0pIVEU5RjJPSmE1M3N3In0.eyJleHAiOjE2MTQyODk4NTEsImlhd
CI6MTYxNDI3NTQ1MSwianRpIjoiMDQ4ZjhlMjctZTgwZi00MjIyLWFmNDAtMjZlNDdmYTFhMDg0Iiwi
aXNzIjoiaHR0cHM6Ly8zNS4xOTAuNTkuNzkvYXV0aC9yZWFsbXMvSURQIiwiYXVkIjoiSURQIiwic3V
iIjoiZjZiNGY1ZDQtMzM2Yi00ZTE3LTg3NzYtYzYwNWU3MzU0Y2JiIiwidHlwIjoiQmVhcmVyIiwiYX
pwIjoiSURQIiwic2Vzc2lvbl9zdGF0ZSI6ImYzYmZlOGJiLTFiZGYtNDQ5OS04NDQwLWIxODk5OGYwY
jg5NiIsImFjciI6IjEiLCJzY29wZSI6IiIsIm5iZiI6MCwicm9sZSI6IntcImdlby5pZHAubm90aWZ5
XCI6W1widXNlclwiXSxcImdlby5hcHAub2FkXCI6W1widXNlclwiXSxcImdlby5pZHAuZGF0YXN0b3J
lXCI6W1widXNlclwiXSxcImdlby5hcHAud29ya2JlbmNoXCI6W1widXNlclwiXX0iLCJyb2xlcyI6ey
JnZW8uaWRwLm5vdGlmeSI6WyJ1c2VyIl0sImdlby5hcHAub2FkIjpbInVzZXIiXSwiZ2VvLmlkcC5kY
XRhc3RvcmUiOlsidXNlciJdLCJnZW8uYXBwLndvcmtiZW5jaCI6WyJ1c2VyIl19LCJzdWlkIjoiMTE4
NjUxMzU0NiIsInV1aWQiOiI3OWI4NDE2ZS02NDQ2LTRjMGMtYTg4NS1mNTMxNmRjMzljMmUiLCJsb2E
iOjEwMH0.XHwxx3TzNNwgzVMv18Jav4bqXW9Q4n2bP_HV1iy0K4VPH-w84tXsHjXfH_f05Ynn2CXqv-
rdHds6KtuZaI1aypNnIvNvmbUiNHd6M1geLY4w8Yy9rg9-WFjYiFXbLTP7vvUAMSHueJmeT6WvzAsUT
Z7IQdp0w5aLDQ6ElV8pX1khBMCC7uXedRRDK-UC1MlJBrWtbhIMu5MaqpdpPeBcBMCvmqUBFTFfW6dQ
Ko01jeDjxePz_gZ2wdyU8fkV8UNTzkS3i6PYUkcxi3pmEC5r93JSNGVRUsZ53y5IjcaJK4aRXvvZQzV
iOitsbu8Pfciii2E_NDlk3qYgSqlxVrmzNA","expires_in":14400,"refresh_expires_in":0,
"token_type":"bearer","not-before-policy":0,"session_state":"f3bfe8bb-1bdf-4499
-8440-b18998f0b896","scope":""}
Notice the content length is now 1453 characters. The difference is with the token information inside the JSON response. It should be 1330 characters, but is only 1283 characters. The rest of the JSON document is the same. And the returned token is not valid for further use.
I can't find any explanation as to why the response is shorter when requested from UTL_HTTP. I first thought it had something to do with character set encoding. I have everything set to UTF-8. The token is returned in a base64 encoding.
Here is the code I use (I did not include the debugging code):
-- Setup the http request type and add the content
http_req := utl_http.begin_request(url, 'POST', 'HTTP/1.0');
utl_http.set_header(http_req, 'Content-Type', content_type);
utl_http.set_body_charset(http_req,'UTF-8');
utl_http.set_header(http_req, 'Content-Length', length(post_content));
utl_http.write_text(http_req, post_content);
-- Call the REST endpoint and fetch the http response
http_resp := utl_http.get_response(http_req);
utl_http.set_body_charset(http_resp,'UTF-8');
-- Read the response content
begin
json_response := '';
i := 0;
loop
utl_http.read_line(http_resp, response_line, false);
json_response := json_response || response_line;
i := i + 1;
end loop;
exception
when utl_http.end_of_body then
utl_http.end_response(http_resp);
end;
I have been staring at this problem for hours. I tried various things, like setting or not setting explicit character set encoding, all to not effect. I can't see what I'm doing wrong and why Oracle would do anything with the response. I could imagine it truncating it for some reason - but why would characters be removed from inside the response ?
I'm slightly ashamed. The answer is simple: in the begin_request() call I was explicitly specifying the HTTP 1.0 protocol:
http_req := utl_http.begin_request(url, 'POST', 'HTTP/1.0');
Once I got rid of that (which means Oracle uses the HTTP 1.1 protocol):
http_req := utl_http.begin_request(url, 'POST');
Then everything started working correctly: I now get the full and entire response from the server.
There is still an oddity, in that when I do curl --http1.0 to also force use of HTTP 1.0, I still get the right answer. So I assume that there is something inside the Oracle implementation that causes trouble when using HTTP 1.0 on some workloads.

Chrome is closing my ajax post at exactly 60 seconds

I am submitting some information that takes longer than 60 seconds to process, for some reason Chrome is closing that connection at exactly 1 minute. We also have the page cached with Akamai but they say that their timeout is 120 seconds, so something else must be causing the problem. We don't have timeouts in our angular code or anywhere close. Here is the output from Chrome's net internals. This only happens in Chrome, IE and Firefox process the submit fine.
t=191705 [st= 0] +REQUEST_ALIVE [dt=60081]
t=191705 [st= 0] URL_REQUEST_DELEGATE [dt=0]
t=191705 [st= 0] +URL_REQUEST_START_JOB [dt=60080]
--> load_flags = 672000 (BYPASS_DATA_REDUCTION_PROXY | MAYBE_USER_GESTURE | REPORT_RAW_HEADERS | VERIFY_EV_CERT)
--> method = "POST"
--> priority = "LOW"
--> upload_id = "0"
--> url = "https://qa2.web.com/payment/submit"
t=191705 [st= 0] URL_REQUEST_DELEGATE [dt=0]
t=191706 [st= 1] HTTP_CACHE_GET_BACKEND [dt=0]
t=191706 [st= 1] URL_REQUEST_DELEGATE [dt=0]
t=191706 [st= 1] +HTTP_STREAM_REQUEST [dt=0]
t=191706 [st= 1] HTTP_STREAM_REQUEST_BOUND_TO_JOB
--> source_dependency = 4578 (HTTP_STREAM_JOB)
t=191706 [st= 1] -HTTP_STREAM_REQUEST
t=191706 [st= 1] +HTTP_TRANSACTION_SEND_REQUEST [dt=0]
t=191706 [st= 1] HTTP_TRANSACTION_HTTP2_SEND_REQUEST_HEADERS
--> :host: qa2.web.com
:method: POST
:path: /payment/submit
:scheme: https
:version: HTTP/1.1
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate
accept-language: en-US,en;q=0.8
content-length: 317
content-type: application/json;charset=UTF-8
cookie: [2043 bytes were stripped]
origin: https://qa2.web.com
referer: https://qa2.web.com/payment/submit
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36
t=191706 [st= 1] -HTTP_TRANSACTION_SEND_REQUEST
t=191706 [st= 1] +HTTP_TRANSACTION_READ_HEADERS [dt=60079]
t=191706 [st= 1] HTTP2_STREAM_UPDATE_SEND_WINDOW
--> delta = -317
--> stream_id = 313
--> window_size = 65219
t=251785 [st=60080] HTTP2_STREAM_ERROR
--> description = "SPDY stream closed with status: 6"
--> status = -337
--> stream_id = 313
t=251785 [st=60080] -HTTP_TRANSACTION_READ_HEADERS
--> net_error = -337 (ERR_SPDY_PROTOCOL_ERROR)
t=251785 [st=60080] -URL_REQUEST_START_JOB
--> net_error = -337 (ERR_SPDY_PROTOCOL_ERROR)
t=251786 [st=60081] URL_REQUEST_DELEGATE [dt=0]
t=251786 [st=60081] -REQUEST_ALIVE
--> net_error = -337 (ERR_SPDY_PROTOCOL_ERROR)
Here's a quick workaround for ERR_SPDY_PROTOCOL_ERROR:
Open a new tab in your Chrome browser
As URL enter: chrome://net-internals/#events&q=type:SPDY_SESSION%20is:active
Click on the arrow in the right corner
From the drop-down menu click on flush sockets
Try the affected URL again
In your case, maybe it would be necessary to diagnose your application behavior in-depth and why this behavior triggers this issue.
Regards

Typhoeus gem is not fetching the primary IP

I am using Typhoeus gem to run HTTP request. But when I am running in another system its running fine and returning the correct primary IP. But in my system it's not giving the primary IP -- instead of that it returns nil.
My code is like
request = Typhoeus.post("www.google.com")
response in another system:
Typhoeus::Response:0xb45c1f70 #options={:httpauth_avail=>0, :total_time=>0.101638, :starttransfer_time=>0.10146, :appconnect_time=>0.0, :pretransfer_time=>0.035663, :connect_time=>0.035659, :namelookup_time=>0.00018, :effective_url=>"http://www.google.com", :primary_ip=>"74.125.236.48", :response_code=>405, :redirect_count=>0, :return_code=>:ok,
response in my system:
Typhoeus::Response:0xbc9704c #options={:httpauth_avail=>0, :total_time=>0.589821, :starttransfer_time=>0.419524, :appconnect_time=>nil, :pretransfer_time=>0.194883, :connect_time=>0.194829, :namelookup_time=>0.02522, :effective_url=>"http://www.google.com", :primary_ip=>nil, :response_code=>200, :redirect_count=>0, :return_code=>:ok,
I want to know why its happening like this. I am waiting for good answer.
UPDATED
FULL RESPONSE from another system:
Typhoeus::Response:0xb4cebdb4 #options={:httpauth_avail=>0, :total_time=>0.077503, :starttransfer_time=>0.077249, :appconnect_time=>0.0, :pretransfer_time=>0.013626, :connect_time=>0.01362, :namelookup_time=>0.000143, :effective_url=>"http://www.google.com", :primary_ip=>"74.125.236.50", :response_code=>405, :redirect_count=>0, :return_code=>:ok, :response_headers=>"HTTP/1.1 405 Method Not Allowed\r\nAllow: GET, HEAD\r\nDate: Thu, 10 Apr 2014 12:42:44 GMT\r\nContent-Type: text/html; charset=UTF-8\r\nServer: gws\r\nContent-Length: 1453\r\nX-XSS-Protection: 1; mode=block\r\nX-Frame-Options: SAMEORIGIN\r\nAlternate-Protocol: 80:quic\r\n\r\n", :response_body=>"\n\n \n \n Error 405 (Method Not Allowed)!!1\n \n {margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px} > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}#media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/errors/logo_sm_2.png) no-repeat}#media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/errors/logo_sm_2_hr.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/errors/logo_sm_2_hr.png) 0}}#media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/errors/logo_sm_2_hr.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:55px;width:150px}\n \n \n 405. That\xE2\x80\x99s an error.\n The request method POST is inappropriate for the URL /. That\xE2\x80\x99s all we know.\n", :debug_info=>#}, #request=#:post}, #options={:method=>:post, :headers=>{"User-Agent"=>"Typhoeus - https://github.com/typhoeus/typhoeus"}, :maxredirs=>50}, #on_headers=[], #response=#, #on_complete=[], #on_failure=[]>
FULL RESPONSE from MY system:
Typhoeus::Response:0xbf277e4 #options={:httpauth_avail=>0, :total_time=>0.542332, :starttransfer_time=>0.374829, :appconnect_time=>nil, :pretransfer_time=>0.192083, :connect_time=>0.192035, :namelookup_time=>0.025185, :effective_url=>"http://www.google.com", :primary_ip=>nil, :response_code=>200, :redirect_count=>0, :return_code=>:ok, :response_headers=>"HTTP/1.1 200 OK\r\nDate: Thu, 10 Apr 2014 12:44:38 GMT\r\nExpires: -1\r\nCache-Control: private, max-age=0\r\nContent-Type: text/html; charset=ISO-8859-1\r\nSet-Cookie: PREF=ID=075796115d23a806:FF=0:TM=1397133878:LM=1397133878:S=9K9PiB355V_pLs56; expires=Sat, 09-Apr-2016 12:44:38 GMT; path=/; domain=.google.com\r\nSet-Cookie: NID=67=lbUdPyBSFruSAjPvOJZJhr25WNN43JzP--0oYtYxHvMxYYJqeWZBj8wRZi6qMPxw7XPHHylholrcflVZ-SpIdci8GL_guJcfAnh1O8XJHKQb3Qu67MA62L-bhlCbvgST; expires=Fri, 10-Oct-2014 12:44:38 GMT; path=/; domain=.google.com; HttpOnly\r\nP3P: CP=\"This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info.\"\r\nServer: gws\r\nX-XSS-Protection: 1; mode=block\r\nX-Frame-Options: SAMEORIGIN\r\nAlternate-Protocol: 80:quic\r\nTransfer-Encoding: chunked\r\n\r\n", :response_body=>"http://schema.org/WebPage\" lang=\"en\">Google(function(){\nwindow.google={kEI:\"NpJGU4rKMeWCiQe46IGABA\",getEI:function(a){for(var b;a&&(!a.getAttribute||!(b=a.getAttribute(\"eid\")));)a=a.parentNode;return b||google.kEI},https:function(){return\"https:\"==window.location.protocol},kEXPI:\"17259,4000116,4007661,4007830,4008067,4008133,4008142,4009033,4009565,4009641,4010806,4010858,4010899,4011228,4011258,4011679,4012373,4012504,4012508,4013374,4013414,4013591,4013723,4013747,4013757,4013787,4013823,4013967,4013979,4014016,4014431,4014515,4014636,4014671,4014810,4014813,4014909,4014991,4015119,4015155,4015234,4015260,4015444,4015497,4015519,4015550,4015589,4015638,4015639,4015642,4015644,4015646,4015685,4015772,4015812,4015853,4015900,4016007,4016031,4016127,4016309,4016323,4016326,4016331,4016367,4016373,4016452,4016456,4016466,4016479,4016487,4016623,4016643,4016703,4016730,4016851,4016902,4016969,8300015,8300017,8500165,8500223,8500239,8500252,8500256,8500283,8500306,10200002,10200012,10200013,10200029,10200038,10200040,10200045,10200048,10200053,10200055,10200066,10200083,10200103,10200120,10200134,10200136,10200155,10200157,10200159,10200178\",kCSI:{e:\"17259,4000116,4007661,4007830,4008067,4008133,4008142,4009033,4009565,4009641,4010806,4010858,4010899,4011228,4011258,4011679,4012373,4012504,4012508,4013374,4013414,4013591,4013723,4013747,4013757,4013787,4013823,4013967,4013979,4014016,4014431,4014515,4014636,4014671,4014810,4014813,4014909,4014991,4015119,4015155,4015234,4015260,4015444,4015497,4015519,4015550,4015589,4015638,4015639,4015642,4015644,4015646,4015685,4015772,4015812,4015853,4015900,4016007,4016031,4016127,4016309,4016323,4016326,4016331,4016367,4016373,4016452,4016456,4016466,4016479,4016487,4016623,4016643,4016703,4016730,4016851,4016902,4016969,8300015,8300017,8500165,8500223,8500239,8500252,8500256,8500283,8500306,10200002,10200012,10200013,10200029,10200038,10200040,10200045,10200048,10200053,10200055,10200066,10200083,10200103,10200120,10200134,10200136,10200155,10200157,10200159,10200178\",ei:\"NpJGU4rKMeWCiQe46IGABA\"},authuser:0,ml:function(){},kHL:\"en\",time:function(){return(new Date).getTime()},log:function(a,b,c,h,k){var d=\nnew Image,f=google.lc,e=google.li,g=\"\";d.onerror=d.onload=d.onabort=function(){delete f[e]};f[e]=d;c||-1!=b.search(\"&ei=\")||(g=\"&ei=\"+google.getEI(h));c=c||\"/\"+(k||\"gen_204\")+\"?atyp=i&ct=\"+a+\"&cad=\"+b+g+\"&zx=\"+google.time();a=/^http:/i;a.test(c)&&google.https()?(google.ml(Error(\"GLMM\"),!1,{src:c}),delete f[e]):(d.src=c,google.li=e+1)},lc:[],li:0,y:{},x:function(a,b){google.y[a.id]=[a,b];return!1},load:function(a,b,c){google.x({id:a+l++},function(){google.load(a,b,c)})}};var l=0;})();\n(function(){google.sn=\"webhp\";google.timers={};google.startTick=function(a,b){google.timers[a]={t:{start:google.time()},bfr:!!b}};google.tick=function(a,b,g){google.timers[a]||google.startTick(a);google.timers[a].t[b]=g||google.time()};google.startTick(\"load\",!0);\ntry{}catch(d){}})();\nvar _gjwl=location;function _gjuc(){var a=_gjwl.href.indexOf(\"#\");if(0<=a&&(a=_gjwl.href.substring(a),0#gbar,#guser{font-size:13px;padding-top:1px !important;}#gbar{height:22px}#guser{padding-bottom:7px !important;text-align:right}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}#media all{.gb1{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:left}}a.gb1,a.gb4{text-decoration:underline !important}a.gb1,a.gb4{color:#00c !important}.gbi .gb4{color:#dd8e27 !important}.gbf .gb4{color:#900 !important}body,td,a,p,.h{font-family:arial,sans-serif}body{margin:0;overflow-y:scroll}#gog{padding:3px 8px 0}td{line-height:.8em}.gac_m td{line-height:17px}form{margin-bottom:20px}.h{color:#36c}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{height:25px;width:496px}.gsfi,.lst{font:18px arial,sans-serif}.gsfs{font:17px arial,sans-serif}.ds{display:inline-box;display:inline-block;margin:3px 0 4px;margin-left:4px}input{font-family:inherit}a.gb1,a.gb2,a.gb3,a.gb4{color:#11c !important}body{background:#fff;color:black}a{color:#11c;text-decoration:none}a:hover,a:active{text-decoration:underline}.fl a{color:#36c}a:visited{color:#551a8b}a.gb1,a.gb4{text-decoration:underline}a.gb3:hover{text-decoration:none}#ghead a.gb2:hover{color:#fff !important}.sblc{padding-top:5px}.sblc a{display:block;margin:2px 0;margin-left:13px;font-size:11px}.lsbb{background:#eee;border:solid 1px;border-color:#ccc #999 #999 #ccc;height:30px}.lsbb{display:block}.ftl,#fll a{display:inline-block;margin:0 12px}.lsb{background:url(/images/srpr/nav_logo80.png) 0 -258px repeat-x;border:none;color:#000;cursor:pointer;height:30px;margin:0;outline:0;font:15px arial,sans-serif;vertical-align:top}.lsb:active{background:#ccc}.lst:focus{outline:none}#addlang a{padding:0 3px}(function(){var src='/images/nav_logo176.png';var iesg=false;document.body.onload = function(){window.n && window.n();if (document.images){new Image().src=src;}\nif (!iesg){document.f&&document.f.q.focus();document.gbqf&&document.gbqf.q.focus();}\n}\n})(); Search http://www.google.com/imghp?hl=en&tab=wi\">Images http://maps.google.com/maps?hl=en&tab=wl\">Maps https://play.google.com/?hl=en&tab=w8\">Play http://www.youtube.com/?tab=w1\">YouTube http://news.google.com/nwshp?hl=en&tab=wn\">News https://mail.google.com/mail/?tab=wm\">Gmail https://drive.google.com/?tab=wo\">Drive http://www.google.com/intl/en/options/\">More »http://www.google.com/history/optout?hl=en\" class=gb4>Web History | Settings | https://accounts.google.com/ServiceLogin?hl=en&continue=http://www.google.com/\" class=gb4>Sign in Advanced searchLanguage toolsAdvertising ProgramsBusiness Solutionshttps://plus.google.com/116899029375914044550\" rel=\"publisher\">+GoogleAbout Google© 2013 - Privacy & Termsif(google.y)google.y.first=[];(function(){function b(a){window.setTimeout(function(){var c=document.createElement(\"script\");c.src=a;document.getElementById(\"xjsd\").appendChild(c)},0)}google.dljp=function(a){google.xjsu=a;b(a)};google.dlj=b;})();\nif(!google.xjs){window._=window._||{};window._._DumpException=function(e){throw e};if(google.timers&&google.timers.load.t){google.timers.load.t.xjsls=new Date().getTime();}google.dljp('/xjs/_/js/k\\x3dxjs.hp.en_US.75bv2nh_qxI.O/m\\x3dsb_he,pcc/rt\\x3dj/d\\x3d1/sv\\x3d1/rs\\x3dAItRSTOX5WMsAVpkgEafYeVKZ7ZCJdNXcg');google.xjs=1;}google.pmc={\"sb_he\":{\"agen\":true,\"cgen\":true,\"client\":\"heirloom-hp\",\"dh\":true,\"ds\":\"\",\"eqch\":true,\"fl\":true,\"host\":\"google.com\",\"jam\":0,\"jsonp\":true,\"msgs\":{\"dym\":\"Did you mean:\",\"lcky\":\"I\\u0026#39;m Feeling Lucky\",\"lml\":\"Learn more\",\"oskt\":\"Input tools\",\"psrc\":\"This search was removed from your \\u003Ca href=\\\"/history\\\"\\u003EWeb History\\u003C/a\\u003E\",\"psrl\":\"Remove\",\"sbit\":\"Search by image\",\"srch\":\"Google Search\"},\"ovr\":{},\"pq\":\"\",\"qcpw\":false,\"scd\":10,\"sce\":5,\"stok\":\"nXO_Z2rNte7VdOqPtwZ_V-hNE4c\"},\"pcc\":{}};google.y.first.push(function(){if(google.med){google.med('init');google.initHistory();google.med('history');}});if(google.j&&google.j.en&&google.j.xi){window.setTimeout(google.j.xi,0);}(function(){if(google.timers&&google.timers.load.t){var b,c,d,e,g=function(a,f){a.removeEventListener?(a.removeEventListener(\"load\",f,!1),a.removeEventListener(\"error\",f,!1)):(a.detachEvent(\"onload\",f),a.detachEvent(\"onerror\",f))},h=function(a){e=(new Date).getTime();++c;a=a||window.event;a=a.target||a.srcElement;g(a,h)},k=document.getElementsByTagName(\"img\");b=k.length;for(var l=c=0,m;l", :debug_info=>#}, #request=#:post}, #options={:method=>:post, :headers=>{"User-Agent"=>"Typhoeus - https://github.com/typhoeus/typhoeus"}, :maxredirs=>50}, #on_headers=[], #response=#, #on_complete=[], #on_success=[]>

Universal Analytics Measurement Protocol 200 - Nothing shows up

Like the title says, nothing shows up in real time events nor in any other event
The request being sent is done with ruby's faraday gem
require 'faraday'
require 'json'
GOOGLE_ANALYTICS_SETTINGS = {}
class GoogleAnalyticsApi
def event(client_id = '555', category, action, label, value, user_agent)
return unless !GOOGLE_ANALYTICS_SETTINGS["tracking_code"].empty?
params = {
v: GOOGLE_ANALYTICS_SETTINGS["version"],
tid: GOOGLE_ANALYTICS_SETTINGS["tracking_code"],
cid: client_id,
t: "event",
ec: category,
ea: action,
el: label,
ev: value
}
begin
puts params
c = Faraday.new() do |f|
f.request :url_encoded
f.response :logger
f.adapter Faraday.default_adapter
end
response = c.post GOOGLE_ANALYTICS_SETTINGS["endpoint"], params, { "User-Agent" => user_agent || "Subscribing Worker theSkimm" }
puts response.headers
puts response.body
return true
rescue Exception => rex
return false
end
end
end
From the console:
{:v=>1, :tid=>"UA-XXXXXXXX-1", :cid=>"1999999999.1389999972", :t=>"event", :ec=>"test-event", :ea=>"test-action", :el=>nil, :ev=>nil}
I, [2014-01-15T18:04:04.555555 #7666] INFO -- : post http://www.google-analytics.com/collect
D, [2014-01-15T18:04:04.555667 #7666] DEBUG -- request: User-Agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.76 Safari/537.36"
Content-Type: "application/x-www-form-urlencoded"
I, [2014-01-15T18:04:04.670273 #7666] INFO -- Status: 200
D, [2014-01-15T18:04:04.670512 #7666] DEBUG -- response: pragma: "no-cache"
expires: "Mon, 07 Aug 1995 23:30:00 GMT"
cache-control: "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"
access-control-allow-origin: "*"
last-modified: "Sun, 17 May 1998 03:00:00 GMT"
x-content-type-options: "nosniff"
content-type: "image/gif"
date: "Wed, 15 Jan 2014 23:04:04 GMT"
server: "Golfe2"
content-length: "35"
alternate-protocol: "80:quic"
connection: "close"
{"pragma"=>"no-cache", "expires"=>"Mon, 07 Aug 1995 23:30:00 GMT", "cache-control"=>"private, no-cache, no-cache=Set-Cookie, proxy-revalidate", "access-control-allow-origin"=>"*", "last-modified"=>"Sun, 17 May 1998 03:00:00 GMT", "x-content-type-options"=>"nosniff", "content-type"=>"image/gif", "date"=>"Wed, 15 Jan 2014 23:04:04 GMT", "server"=>"Golfe2", "content-length"=>"35", "alternate-protocol"=>"80:quic", "connection"=>"close"}
GIF89a�����,D;
For whomever encounters this the problem was setting nil value for el and ev. When the params hash is moved through Faraday the nil valued items get converted to the key name without any value and google didn't like that.
IE a query string with nil values going through Faraday would be:
...&el&ev
Not good for google's Measurement Protocol.

Unable to create s3 bucket in EU region

body = "<CreateBucketConfiguration><LocationConstraint>EU</LocationConstraint></CreateBucketConfiguration>"
content_length = body.bytesize
content_type = "text/plain"
url = URI.parse("http://#{#name}.s3.amazonaws.com/")
req = Net::HTTP::Put.new(url.path)
req.body = body
req.add_field 'Date' , #time
req.add_field 'Host', "#{#name}.s3.amazonaws.com"
req.add_field 'Content-Type', "#{content_type}"
req.add_field 'Authorization', "#{signature}"
req.add_field 'Content-Length', "#{content_length}"
response = Net::HTTP.new(url.host, url.port).start do |http|
http.request(req)
end
puts response.read_body
returns 200 and creates bucket but in U.S Standard and not in EU. What am I missing here? Thanks for the help.
Here is the entire conversation
PUT / HTTP/1.1
Accept: */*
User-Agent: Ruby
Date: Wed, 19 Jan 2011 22:14:31 -0800
Host: mytest.s3.amazonaws.com
Content-Type: text/plain
Authorization: AWS AC8RVKAXAU8Q:41uTqvfncc2mE561YabgpGUouio=
Content-Length: 146
<CreateBucketConfiguration xmlns='http://s3.amazonaws.com/doc/2006-03-01/'>
<LocationConstraint>EU</LocationConstraint>
</CreateBucketConfiguration>
HTTP/1.1 200 OK
x-amz-id-2: lrlPt8Y19ZxFXPbZf9Gf6dYxTGLYkkMzo0tSNXCNk29o9xghcob502mcttQ/oo4W
x-amz-request-id: 3504CCA0E7AFFE95
Date: Thu, 20 Jan 2011 06:14:32 GMT
Location: /mytest
Content-Length: 0
Server: AmazonS3
HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
Date: Thu, 20 Jan 2011 06:14:32 GMT
Connection: close
Server: AmazonS3
0
The only thing that I can see is that you haven't included the xmlns in the request body - not sure if that will make any difference though.
xmlns="http://s3.amazonaws.com/doc/2006-03-01/"
body = "<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><LocationConstraint>EU</LocationConstraint></CreateBucketConfiguration>"

Resources