How can I test a CSP report-uri endpoint? - json

I've added a Content Security Policy to my website and made a report-uri endpoint with AWS API Gateway, Lambda, and DynamoDB. I've tested it with Postman using the following JSON
{
"resource": "/",
"path": "/",
"requestContext": {
"resourcePath": "/",
"httpMethod": "POST",
"path": "/latest"
},
"headers": {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"accept-encoding": "gzip, deflate, br",
"Host": "70ixmpl4fl.execute-api.us-east-2.amazonaws.com",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36",
"X-Amzn-Trace-Id": "Root=1-5e66d96f-7491f09xmpl79d18acf3d050"
},
"multiValueHeaders": {
"accept": [
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
],
"accept-encoding": [
"gzip, deflate, br"
]
},
"queryStringParameters": null,
"multiValueQueryStringParameters": null,
"pathParameters": null,
"stageVariables": null,
"body": {
"csp-report": {
"document-uri": "https://example.com/signup.html",
"referrer": "",
"blocked-uri": "https://example.com/css/style.css",
"violated-directive": "style-src cdn.example.com",
"original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports"
}
},
"isBase64Encoded": false
}
It seems to work properly when using Postman. But when I added the endpoint to my Content Security Policy and attempt to violate the policy, I can't seem to get it to report correctly.
Does the JSON above adequately demonstrate what a real CSP violation would look like?
I've looked around and haven't seen much about developing your own endpoint. Any resources or other advice is greatly appreciated.

It depends on the browser
some browser sends the Json and CSP violation report some sends thec csp-report.
Few browser sends the request base64 encoded.
Specifically in chrome browser it sends base64 encoded and as Json format. In your payload.
Hopefully it answers your question.

Related

can not get X-AppEngine info from req header in 2nd generation AppEngine

I build 2 functions in GoogleCloudFunctions today, with the same code and different environment (1st gen and 2nd gen).
res.json(req.headers)
the 1st generation with X-Appengine-* in headers but 2nd generation don't have it.
1st generation res:
{
"host": "xxxxx",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:106.0) Gecko/20100101 Firefox/106.0",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"accept-encoding": "gzip, deflate, br",
"accept-language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"forwarded": "for=\"xx.xx.xx.xx\";proto=https",
"function-execution-id": "z93h1p8dezsd",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"traceparent": "00-c6fbb14b26a1999f7203caa810bd82bd-f4e8995eb815facc-01",
"upgrade-insecure-requests": "1",
"x-appengine-appversionid": "h~j3d1cb91ff7bbe64cp-tp/a8aa78b2557e1c923250159d17af9995:2.447902922919183830",
"x-appengine-city": "?",
"x-appengine-citylatlong": "0.000000,0.000000",
"x-appengine-country": "HK",
"x-appengine-default-version-hostname": "j3d1cb91ff7bbe64cp-tp.appspot.com",
"x-appengine-https": "on",
"x-appengine-region": "?",
"x-appengine-request-log-id": "63745ec000ff00ff035e0349af4c0001687e6a33643163623931666637626265363463702d7470000161386161373862323535376531633932333235303135396431376166393939353a32000100",
"x-appengine-timeout-ms": "599999",
"x-appengine-user-ip": "xx.xx.xx.xx",
"x-cloud-trace-context": "c6fbb14b26a1999f7203caa810bd82bd/17647523771945712332;o=1",
"x-forwarded-for": "xx.xx.xx.xx",
"x-forwarded-proto": "https",
"connection": "close"
}
2nd generation res:
{
"host": "xxxxx.run.app",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:106.0) Gecko/20100101 Firefox/106.0",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"accept-language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"upgrade-insecure-requests": "1",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"x-cloud-trace-context": "7adcb5fe556c66fc94f83b6dfe62dfe6/5799981330522755859;o=1",
"traceparent": "00-7adcb5fe556c66fc94f83b6dfe62dfe6-507dac4a5db4d313-01",
"x-forwarded-for": "xxx.xxx.xxx.xxx",
"x-forwarded-proto": "https",
"forwarded": "for=\"xxx.xxx.xxx.xxx\";proto=https",
"accept-encoding": "gzip, deflate, br"
}
Could I get X-Appengine-* from 2nd generation Functions?
Thank you
App Engine-specific headers is not supported for second generation environment.Because Cloud Functions (2nd gen) is built on Cloud Run,you can refer to this document
As mentioned by john hanley in above comment If you want those headers, deploy on gen1.
If you think it’s a valid feature request you may raise here with a clear description.Good feature requests will solve common problems or enable new use cases.

POST JSON object to aws lambda

How can I post a json object to aws lambda function through aws API gateway ?
p.s.- My goal is to write the lambda function in python and then post it to aws SQS.
Thanks in advance.
I figured it out. Now I have a API Gateway acceptiong client posted JSON data of a specified format and then passing it to a AWS-Lambda function which, dumps the data into a AWS-SQS. The steps are explained below in details-
STEP 1-
Create a lambda function in any supported languages (I have used Python 3.6). Here is a sample code.
import boto3
import json
def lambda_handler(event, context):
sqs = boto3.resource('sqs')
queue = sqs.get_queue_by_name(QueueName='userData')
response = queue.send_message(MessageBody=json.dumps(event))
return {
"status":"0",
"message":"",
"pubId":event["ClientID"],
"routetitle":event["routeTitle"]
}
Note: I have imported both json and boto3 library which are available in aws context no need to add any more file. Also see that I have not specified any details for SQS other than the name because both of my Lambda function and SQS are in same AWS region. I am dumping the whole "event" variable to SQS as this only contains the posted JSON data.
STEP 2-
Now in the AWS console goto "API Gateway" and then create a new API Gateway and then create a "POST" action under resources.
Please check the screenshot
Now, under the post action, click on "Integration request". Now add a body template to it like the example given below-
{
"userMobile" : "$input.params('userMobile')",
"ClientID" : "$input.params('ClientID')",
"routeTitle" : "$input.params('routeTitle')"
}
Also, make sure that you have the "Integration Type" of your API as "Lambda" and the Lambda function we created in STEP-1 is connected to the API.
Now, we are almost done. now all we have to do is create a stage for the API that we have created and deploy the API. ***
Please note the HTTP URL of the API after deployment.
STEP 3-
Now go to the "Simple Queuing Service (SQS)" and then create a simple SQS with keeping all the default parameters. Make sure the queue name is matching with the one you have provided in your Lambda function and both your Lambda function and your SQS are in same AWS region.
Now, you can POST JSON data in the same format to your API and your Lambda function will dump it to the SQS queue, where you can go and view the data.
You can also test the API using tools like Fidler.
*** make sure to redeploy the API for every time you make a change to it.
Yes you can,
If you trigger the Lambda function from API Gateway using the Lambda Proxy integration the request will call the function with a payload that looks like that below. As you can see all you need to do is parse the JSON body attribute.
{
"resource": /path",
"path": "/path",
"httpMethod": "PUT",
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, sdch, br",
"Accept-Language": "en-US,en;q=0.8,pl;q=0.6,en-GB;q=0.4",
"Cache-Control": "no-cache",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "PL",
"Content-Type": "application/json",
"DNT": "1",
"Host": "api.stockflare.com",
"Origin": "http://localhost:3000",
"Pragma": "no-cache",
"Referer": "http://localhost:3000/databank",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Via": "1.1 XXXXX.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "XXXXXX==",
"X-Amzn-Trace-Id": "Root=XXXXXX",
"X-Forwarded-For": "XXXXX",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"queryStringParameters": null,
"pathParameters": null,
"stageVariables": null,
"requestContext": {
"path": "/path",
"accountId": "XXXXX",
"resourceId": "p0flbp",
"stage": "v1",
"requestId": "XXXXX",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"apiKey": "",
"sourceIp": "XXXXXX",
"accessKey": null,
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"user": null
},
"resourcePath": "/path",
"httpMethod": "PUT",
"apiId": "XXXXXX"
},
"body": "{\"fields\":[\"forecast_pe\"],\"countries\":[\"_all\",\"amer\",\"apac\",\"emea\"],\"sectors\":[\"50\",\"51\"]}",
"isBase64Encoded": false
}

Raw body payload in AWS API Gateway Body Mapping Template

For some reason I'm having a hard time getting the raw body from within the event. It's logging the $input.body as json for a application/json content-type. The docs say that that should contain the raw payload.
Here my Integration Request Body Mapping Template:
{
"body" : $input.json('$'),
"rawBody": $input.body,
"headers": {
#foreach($header in $input.params().header.keySet())
"$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end
#end
},
"method": "$context.httpMethod",
"params": {
#foreach($param in $input.params().path.keySet())
"$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end
#end
},
"query": {
#foreach($queryParam in $input.params().querystring.keySet())
"$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end
#end
}
}
Here's the payload example:
{
"event": {
"body": {
"hello": "meow"
},
"rawBody": {
"hello": "meow"
},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US",
"Cache-Control": "no-cache",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Content-Type": "application/json",
"Host": "7nuy7lymef.execute-api.us-east-1.amazonaws.com",
"Origin": "file://",
"Postman-Token": "0ce7c6f4-3864-c9b4-f2db-739737b2ba49",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Postman/4.2.2 Chrome/47.0.2526.73 Electron/0.36.2 Safari/537.36",
"Via": "1.1 1eea0bca59557555878da4d9775c509f.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "SDjaGcuJ5eVkOMMCn6M3vGaVicA1fuA7h0bUYE4ARlKupO60eeYNFA==",
"X-Forwarded-For": "206.71.230.14, 205.251.250.135",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https",
"x_example_header": "my awesome header"
},
"method": "POST",
"params": {},
"query": {
"example_param": "myawesomeparam"
}
},
"context": {
"callbackWaitsForEmptyEventLoop": false,
"logGroupName": "/aws/lambda/reggi-log-post",
"logStreamName": "2016/06/08/[$LATEST]aad04e0e46614c288ac8ca43d0a95076",
"functionName": "reggi-log-post",
"memoryLimitInMB": "128",
"functionVersion": "$LATEST",
"invokeid": "6e4e1e13-2dc1-11e6-a1f7-4dad3a8eb122",
"awsRequestId": "6e4e1e13-2dc1-11e6-a1f7-4dad3a8eb122",
"invokedFunctionArn": "arn:aws:lambda:us-east-1:562508364089:function:reggi-log-post"
}
}
Is there any way to access the raw body from this request?
Is there any way to change the content-type to accept all types?
The following blog post explains in detail how to get around this problem. https://nicholasjackson.io/2016/12/13/using-graphql-with-aws-lambda/
It's written specifically in the context of GraphQL, but it will work for any content type. In short:
Go to the Binary Support section. Enable binary support for your chosen media type and save.
Return to the your method in Resources section and open Integration Request. Add/edit the body mapping template for your chosen content type and put the following:
"rawBody": "$util.escapeJavaScript($util.base64Decode($input.body))"
Save and redeploy the API.
Adding binary support encodes the request as a base64 string. The body mapping template decodes it.
$input.body contains the raw payload. You need to put quotes around it like "rawBody": "$input.body". Otherwise the body will be interpreted as part of the json document.

How do I get a html post request to use a specific charset?

I am trying to post a form using an encoding that was previously chosen by the recipient.
The problem I am facing is that I can't seem to get the encoding of the swedish characters åäö to be translated correctly. Consider the following form:
<form accept-charset="ISO-8859-1" action="http://httpbin.org/post" method="post" id="aForm">
<input type="hidden" name="hej" value="köttfärssås"/>
<input type="submit"/>
</form>
Posting this using Chrome gives me the following result:
{
"args": {},
"data": "",
"files": {},
"form": {
"hej": "k\ufffdttf\ufffdrss\ufffds"
},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "sv-SE,sv;q=0.8,en-US;q=0.6,en;q=0.4",
"Cache-Control": "max-age=0",
"Content-Length": "21",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"Origin": "null",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36"
},
"json": null,
"origin": "85.119.130.112",
"url": "http://httpbin.org/post"
}
Not only are the åäö characters jumbled, there are no headers here showing which encoding is being used. What am I missing here?
I have also tried using <meta charset="ISO-8859-1"> and <meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1">, but with no success.
So, how do I force the form to use the encoding of my choice?

Why is a media upload breaking my app assocation (in firefox)?

My javascript app creates a file and then uploads the media content. In Chrome, everything is hunky dorey. In Firefox, the act of uploading media is somehow breaking the association Drive holds between the file and my app, such that the icon is no longer my application icon (it's the default Google blue box) and clicking to open the file gives an error page.
So the steps are ...
Create the file (POST to /files)
Observe in Drive that the file exists and is displayed with my application icon
Upload the file contents (PUT with uploadType=media and convert=false)
Observe in Drive that the file's icon is now the Google blue
If I do exactly the same in Chrome, at step 4, the file is still associated with my app and displays my app icon.
Here is the media PUT from Chrome (ie the working one)
PUT https://content.googleapis.com/upload/drive/v2/files/0B6B-RNrxsCu2SERMMEFXMkdiOWM?uploadType=media&convert=false&useContentAsIndexableText=true&key=AIzaSyCt2bxTnrxo_IGvSUCBBAN_-29HJnzX_MU HTTP/1.1
:host: content.googleapis.com
x-origin: http://foo.myapp.appspot.com
x-javascript-user-agent: google-api-javascript-client/1.1.0-beta
x-goog-encode-response-if-executable: base64
user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
accept-language: en-US,en;q=0.8,en-AU;q=0.6
authorization: Bearer ya29.AHES6ZQq1wAGltlEsnGKr6Dgtgkvp4zHCJsNTrXohnqrRmm3Ji8Yb14
x-referer: http://foo.myapp.appspot.com
x-clientdetails: appVersion=5.0%20(X11%3B%20Linux%20x86_64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F28.0.1500.95%20Safari%2F537.36&platform=Linux%20x86_64&userAgent=Mozilla%2F5.0%20(X11%3B%20Linux%20x86_64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F28.0.1500.95%20Safari%2F537.36
referer: https://content.googleapis.com/static/proxy.html?jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en.l49lMhuyXyk.O%2Fm%3D__features__%2Fam%3DEQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAItRSTOvD2NxxPLz0HiGHMXTek7IhOVTHg
content-length: 9
:version: HTTP/1.1
origin: https://content.googleapis.com
accept-encoding: gzip,deflate,sdch
:path: /upload/drive/v2/files/0B6B-RNrxsCu2SERMMEFXMkdiOWM?uploadType=media&convert=false&useContentAsIndexableText=true&key=AIzaSyCt1bxTnrxo_IGvSUCBBAN_-29HJnzX_MU
content-type: text/html
accept: */*
:scheme: https
:method: PUT
Query String
uploadType=media
&convert=false
&useContentAsIndexableText=true
&key=AIzaSyCt2bxTnrxo_IGvSUCBBAN_-29HJnzX_MU
and here is the media PUT from Firefox (ie. the one that breaks the file association)
firefox
PUT /upload/drive/v2/files/0B6B-RNrxsCu2UFZxbjExd0dGeTQ?uploadType=media&convert=false&useContentAsIndexableText=true&key=AIzaSyCt2bxTnrxo_IGvSUCBBAN_-29HJnzX_MU HTTP/1.1
Host: content.googleapis.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:21.0) Gecko/20100101 Firefox/21.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: text/html; charset=UTF-8
Authorization: Bearer ya29.AHES6ZQrG_PQOmEZD4cBwgrjiNKNZUBc2RzAnOTmZwTJReX664MWvu8
X-ClientDetails: appVersion=5.0%20(X11)&platform=Linux%20x86_64&userAgent=Mozilla%2F5.0%20(X11%3B%20Linux%20x86_64%3B%20rv%3A21.0)%20Gecko%2F20100101%20Firefox%2F21.0
X-JavaScript-User-Agent: google-api-javascript-client/1.1.0-beta
X-Origin: http://foo.myapp.appspot.com
X-Referer: http://foo.myapp.appspot.com
X-Goog-Encode-Response-If-Executable: base64
Referer: https://content.googleapis.com/static/proxy.html?jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en.l49lMhuyXyk.O%2Fm%3D__features__%2Fam%3DEQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAItRSTOvD2NxxPLz0HiGHMXTek7IhOVTHg
Content-Length: 12
Connection: keep-alive
convert false
key AIzaSyCt2bxTnrxo_IGvSUCBBAN_-29HJnzX_MU
uploadType media
useContentAsIndexableText true
The responses are below. The only difference between the return Item json is that the Chrome version has a mimetype "text/html" whereas Firefox has mimetype "text/html; charset=UTF-8"
firefox response
Content-Length 2986
Content-Type application/json
Date Sat, 24 Aug 2013 10:44:37 GMT
Etag "NaUPR8AuDOKgpQqXUqmAHnRC-Nk/R_dzQ2tl2e997lu1SqOGTX63YoE"
Server HTTP Upload Server Built on Aug 7 2013 16:51:13 (1375919473)
X-Firefox-Spdy 3
"kind":"drive#file",
"id":"0B6B-RNrxsCu2cjlldTNoV01JVHc",
"etag":"\"NaUPR8AuDOKgpQqXUqmAHnRC-Nk/NM5C-3sulAfFZA1V-IIsA-E9_AA\"",
"selfLink":"https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2cjlldTNoV01JVHc",
"webContentLink":"https://docs.google.com/uc?id=0B6B-RNrxsCu2cjlldTNoV01JVHc&export=download",
"alternateLink":"https://docs.google.com/file/d/0B6B-RNrxsCu2cjlldTNoV01JVHc/edit?usp=drivesdk",
"iconLink":"https://ssl.gstatic.com/docs/doclist/images/icon_10_generic_list.png",
"thumbnailLink":"https://lh3.googleusercontent.com/1KctCx9tjxe6vSn7piLUzfYQuNKQVzMUd6Phn8dTdlHKfQlQsXi77PyOOLkwS-0q3g=s220",
"title":"burcu",
"mimeType":"text/html; charset=UTF-8",
"labels":{
"starred":false,
"hidden":false,
"trashed":false,
"restricted":false,
"viewed":true
},
"createdDate":"2013-08-24T10:44:12.851Z",
"modifiedDate":"2013-08-24T10:44:36.440Z",
"modifiedByMeDate":"2013-08-24T10:44:36.440Z",
"lastViewedByMeDate":"2013-08-24T10:44:36.440Z",
"parents":[
{
"kind":"drive#parentReference",
"id":"0B6B-RNrxsCu2RVVQZ1NFWGZYUW8",
"selfLink":"https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2cjlldTNoV01JVHc/parents/0B6B-RNrxsCu2RVVQZ1NFWGZYUW8",
"parentLink":"https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2RVVQZ1NFWGZYUW8",
"isRoot":false
},
{
"kind":"drive#parentReference",
"id":"0B6B-RNrxsCu2MFZ0dEx6a2xEQU0",
"selfLink":"https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2cjlldTNoV01JVHc/parents/0B6B-RNrxsCu2MFZ0dEx6a2xEQU0",
"parentLink":"https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2MFZ0dEx6a2xEQU0",
"isRoot":false
}
],
"downloadUrl":"https://doc-0k-54-docs.googleusercontent.com/docs/securesc/i6kcvi4n5dug3hk78lqkpogagkdpecs6/krhjojomqafnrdg6943a1fhtnfjg4b8v/1377338400000/15125351317662028975/15125351317662028975/0B6B-RNrxsCu2cjlldTNoV01JVHc?h=16653014193614665626&e=download&gd=true",
"userPermission":{
"kind":"drive#permission",
"etag":"\"NaUPR8AuDOKgpQqXUqmAHnRC-Nk/ajH3QRzRTY6aEeYY5k2JAipDckI\"",
"id":"me",
"selfLink":"https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2cjlldTNoV01JVHc/permissions/me",
"role":"owner",
"type":"user"
},
"originalFilename":"burcu",
"fileExtension":"",
"md5Checksum":"47088846bea0768b700fa76afc1e2aee",
"fileSize":"6",
"quotaBytesUsed":"6",
"ownerNames":[
" Demo"
],
"owners":[
{
"kind":"drive#user",
"displayName":" Demo",
"isAuthenticatedUser":true,
"permissionId":"15125351317662028975"
}
],
"lastModifyingUserName":" Demo",
"lastModifyingUser":{
"kind":"drive#user",
"displayName":" Demo",
"isAuthenticatedUser":true,
"permissionId":"15125351317662028975"
},
"editable":true,
"copyable":true,
"writersCanShare":true,
"shared":false,
"appDataContents":false,
"headRevisionId":"0B6B-RNrxsCu2MWN5clphQUlBNStwM1FLTWZWS3R0RkViVkh3PQ"
}
chrome response
content-length:
2977
content-type:
application/json
date:
Sat, 24 Aug 2013 10:48:29 GMT
etag:
"NaUPR8AuDOKgpQqXUqmAHnRC-Nk/pESqU9sAUSQgLet1Hkz2wJT0Nyw"
server:
HTTP Upload Server Built on Aug 7 2013 16:51:13 (1375919473)
status:
200 OK
version:
HTTP/1.1
{
"kind": "drive#file",
"id": "0B6B-RNrxsCu2cjlldTNoV01JVHc",
"etag": "\"NaUPR8AuDOKgpQqXUqmAHnRC-Nk/7kdHmkAGWmpQ_v_pNZFbF-GLMic\"",
"selfLink": "https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2cjlldTNoV01JVHc",
"webContentLink": "https://docs.google.com/uc?id=0B6B-RNrxsCu2cjlldTNoV01JVHc&export=download",
"alternateLink": "https://docs.google.com/file/d/0B6B-RNrxsCu2cjlldTNoV01JVHc/edit?usp=drivesdk",
"iconLink": "https://ssl.gstatic.com/docs/doclist/images/icon_10_generic_list.png",
"thumbnailLink": "https://lh4.googleusercontent.com/AXTF6nVY78BZi00eTaAEwmdTfeXVC5Ny3zYEIVEPOTwPNGqy7LC9dKiqzZBg9-q3LA=s220",
"title": "burcu",
"mimeType": "text/html",
"labels": {
"starred": false,
"hidden": false,
"trashed": false,
"restricted": false,
"viewed": true
},
"createdDate": "2013-08-24T10:44:12.851Z",
"modifiedDate": "2013-08-24T10:48:27.913Z",
"modifiedByMeDate": "2013-08-24T10:48:27.913Z",
"lastViewedByMeDate": "2013-08-24T10:48:27.913Z",
"parents": [
{
"kind": "drive#parentReference",
"id": "0B6B-RNrxsCu2RVVQZ1NFWGZYUW8",
"selfLink": "https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2cjlldTNoV01JVHc/parents/0B6B-RNrxsCu2RVVQZ1NFWGZYUW8",
"parentLink": "https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2RVVQZ1NFWGZYUW8",
"isRoot": false
},
{
"kind": "drive#parentReference",
"id": "0B6B-RNrxsCu2MFZ0dEx6a2xEQU0",
"selfLink": "https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2cjlldTNoV01JVHc/parents/0B6B-RNrxsCu2MFZ0dEx6a2xEQU0",
"parentLink": "https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2MFZ0dEx6a2xEQU0",
"isRoot": false
}
],
"downloadUrl": "https://doc-0k-54-docs.googleusercontent.com/docs/securesc/i6kcvi4n5dug3hk78lqkpogagkdpecs6/krhjojomqafnrdg6943a1fhtnfjg4b8v/1377338400000/15125351317662028975/15125351317662028975/0B6B-RNrxsCu2cjlldTNoV01JVHc?h=16653014193614665626&e=download&gd=true",
"userPermission": {
"kind": "drive#permission",
"etag": "\"NaUPR8AuDOKgpQqXUqmAHnRC-Nk/ajH3QRzRTY6aEeYY5k2JAipDckI\"",
"id": "me",
"selfLink": "https://content.googleapis.com/drive/v2/files/0B6B-RNrxsCu2cjlldTNoV01JVHc/permissions/me",
"role": "owner",
"type": "user"
},
"originalFilename": "burcu",
"fileExtension": "",
"md5Checksum": "423f5e2804f551616956ca8cb4a684b0",
"fileSize": "9527",
"quotaBytesUsed": "9527",
"ownerNames": [
" Demo"
],
"owners": [
{
"kind": "drive#user",
"displayName": " Demo",
"isAuthenticatedUser": true,
"permissionId": "15125351317662028975"
}
],
"lastModifyingUserName": " Demo",
"lastModifyingUser": {
"kind": "drive#user",
"displayName": " Demo",
"isAuthenticatedUser": true,
"permissionId": "15125351317662028975"
},
"editable": true,
"copyable": true,
"writersCanShare": true,
"shared": false,
"appDataContents": false,
"headRevisionId": "0B6B-RNrxsCu2Zmg1M0todDBPcERUREtmTjZuQjlCQjJIOUVJPQ"
}
I'll answer my own question by saying this is a bug.
To summarise, using the GAPI Javascript client with Firefox to update content is causing the mime-type in Drive to include the character set (eg. "text/html; charset=UTF-8"). Because this doesn't match the mime-type declared in the API Console ("text/html"), the Drive webapp doesn't associate the file with my application.
The bug could be deemed to be in one of three places:-
It could be a GAPI JS client bug that it is setting the content-type header to be "text/html; charset=UTF-8".
It could be a Drive SDK bug, that the file mime type should always be the one I explicitly declared when I created the file, and should ignore the mime type header of any media uploads. Or it could be considered that the Drive SDK should strip the character set from the content-type header before using it to set the mime type on the file.
It could be a Drive webapp bug, that it should consider "text/html" and "text/html; charset=UTF-8" to be the same mime type.