Parsing HTTP multipart POST using a struct in Rocket [duplicate] - forms

This question already has answers here:
How to parse multipart forms using abonander/multipart with Rocket?
(2 answers)
Closed 5 years ago.
I want to parse a HTTP POST in Rocket using a struct. Upon submitting the form it fails.
I read the body data example and have this code.
#[derive(FromForm)]
struct ConvertFile {
name: String,
filename: String
}
#[post("/submit", format = "multipart/form-data", data = "<form>")]
fn submit(form: Form<ConvertFile>) {
println!("form field: {}", form.get().name);
}
I submit using curl:
curl -H "Content-Type: multipart/form-data" -F "name=Claus" -F "filename=claus.jpg" http://localhost:8000/submit
and the Rocket console responds with
multipart/form-data; boundary=------------------------8495649d6ed34d20:
=> Matched: POST /submit multipart/form-data
=> Warning: Form data does not have form content type.
=> Outcome: Forward
=> Error: No matching routes for POST /submit multipart/form-data; boundary=------------------------8495649d6ed34d2.
=> Warning: Responding with 404 Not Found catcher.
=> Response succeeded.
I want to submit a file hence the multipart/form-data. When trying to find the reason, I used a String in the struct to make it simpler. So first it responds with a Matched: and then no matching routes.
This simpler POST works:
#[post("/convert", format = "text/plain", data = "<file>")]
fn convert_file(file: String) {
println!("file: {}", file);
}
I am using the latest nightly Rust with rustup.
What am I doing wrong?

Rocket does not yet support multipart forms.
You can see the tracking issue here: https://github.com/SergioBenitez/Rocket/issues/106
A possible workaround is given in this answer: How to parse multipart forms using abonander/multipart with Rocket?

Related

Parse 'form-data' from incoming webhook using Google Apps Script

I have a (mulitlevel?) webhook sending into a Google Script (Access:" Anyone"/"Anyone even anonymous") and trying to pull the info out of it with a doPost(). I've used ngrok to capture a sample but can't make it work. I'm trying to extract event but getting errors like
'TypeError Cannot read property 'contents' of undefined'.
I'm using this as one possible starting point to parse it.
function doPost(e) {
try{
var data = JSON.parse(e.postData.contents);
var event = data.event;
} catch(err){
var mykey = '*************************************8'
var dataURL = 'https://maker.ifttt.com/trigger/Data_Check_WHook/with/key/'+mykey+'?value1=Error:&value2=error: '+event
UrlFetchApp.fetch(dataURL);
}
Below a sample of the webhook. Do I need to access 'payload' before reading 'event'?
Content-Disposition: form-data; name="payload"
Content-Type: application/json
{"event":"media.pause","user":true,"owner":true,"Account":********************************Hours_2973","summary":"","viewOffset":1391000,"lastViewedAt":1592403577,"year":2019,"thumb":"/library/metadata/5448/thumb/1572876947","art":"/library/metadata/5448/art/1572876947","originallyAvailableAt":"2019-08-15","addedAt":1560188503,"updatedAt":1572876947,"createdAtAccuracy":"epoch","createdAtTZOffset":"3600"}}
--------------------------55b945c1eb00cab0--

Add flag to UnityWebRequest

I am trying to make a POST request to webpage that expects the --data field to be filled with some data to be processed. I'm pretty much trying to recreate this curl request, but with UnityWebRequest.
curl -X POST http://localhost:8000/clic/say?text=Make+the+gene+set --data '{"geneSetMembers":["UST"],"geneSetName":"selection0"}'
The UnityWebRequest documentation mentions that GET requests don't set any flags other than the url, but it's not clear if no other custom options exist for posts. Is there some way to format a WWWform or something that will hold the data such that the server will recognize it?
var form = new WWWForm();
// some way to plug in the jsonified data to the form
webRequest = UnityWebRequest.Post(url + route + to_say, form);
webRequest.downloadHandler = new DownloadHandlerBuffer();
webRequest.SetRequestHeader("Content-Type", "application/json");
webRequest.SendWebRequest();
// etc etc
I've tried just giving the form a field named "data" a la
form.AddField("data", "{ \"geneSetMembers\":[\"UST\"],\"geneSetName\":\"selection0\"}");
but the server does not like it, saying it "got error Invalid JSON literal name: data" So clearly that's the wrong syntax for it
EDIT: put lines in the same order they were in original code. Sorry, I have commented lines between them
Maybe your server doesn't like to receive the data as a field called data.
This ofcourse depends totally on the PHP code we don't see since you didn't share that part. b
But at least I can tell you that --data or also simply -d in curl refer to the entire data section and is not a field called data.
You could try to instead use a MultiPartFormDataSection passing just the data itself without a specific field name
var data = "{\"geneSetMembers\":[\"UST\"],\"geneSetName\":\"selection0\"}";
var form = new List<IMultiFormPart>{ new MultiPartFormDataSection(data) };
webRequest = UnityWebRequest.Post(url + route + to_say, form);
yield return webRequest.SendWebRequest();
which is now sent as content-type multipart/form-data though ...
Another alternative if your server really needs to receive a content-type application/json might be to "manually" compose the request e.g. like
var data = "{\"geneSetMembers\":[\"UST\"],\"geneSetName\":\"selection0\"}";
var request = new UnityWebRequest(url + route + to_say, "POST");
var bodyRaw = Encoding.UTF8.GetBytes(data);
request.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
request.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
Though of you look close now this seems actually not to be the case since if you read the man curl
(HTTP) Sends the specified data in a POST request to the HTTP server, in the same way that a browser does when a user has filled in an HTML form and presses the submit button. This will cause curl to pass the data to the server using the content-type application/x-www-form-urlencoded
which is actually exactly the default content type used by the simple string version of UnityWebRequest.Post.
So thinking about it it should actually be as simple as using the pure string version of UnityWebRequest.Post:
var data = "{\"geneSetMembers\":[\"UST\"],\"geneSetName\":\"selection0\"}";
var request = UnityWebRequest.Post(url + route + to_say, data);
yield return request.SendWebRequest();

Akka Http - Getting Multipart Form Data

I am creating Post Call using Akka-Http where user will fill the form and make a request.
I want to convert this form data to Scala Map[String, String]
Can any one tell how to do this.
here is the code Snippet
post {
entity(as[Multipart.FormData]) { body =>
complete { //How to process Multi Part Form data to Map
}
}
}
Thanks
Looks like you're looking for the formFieldMap directive.
(post & formFieldMap) { fields =>
doStuffWith(fields)
complete(...)
}
See the docs for more info.

Parse request body with custom content-type to json in Play Framework

I'm using play to proxy my API calls from the ui. For example POST:
def post(url: String) = Action { implicit request =>
Async {
WS.url(proxyUrl + request.uri)
.withQueryString(request.queryString.mapValues(_.head).toSeq: _*)
.withHeaders(request.headers.toMap.mapValues(_.head).toSeq: _*)
.post(request.body.asJson).map(response => Ok(response.body))
}
}
but this can only handle "application/json" and "text/json" content types. But now I want to make requests with custom content type: "application/vnd.MyCustomType-v1+json;charset=utf-8" and of course it doesn't work with current implementation. Have tried different solutions, but nothing seems to work. Any ideas?
I'm using play 2.1
The source for the json body parser looks like this:
def json(maxLength: Int): BodyParser[JsValue] = when(
_.contentType.exists(m => m.equalsIgnoreCase("text/json") || m.equalsIgnoreCase("application/json")),
tolerantJson(maxLength),
createBadResult("Expecting text/json or application/json body")
)
tolerantJson is, itself, a body parser that does the json parsing without a check of the content-type header, so you should just be able to use that to parse your request instead of parse.json.
If you want to go further and have a parser that checks your specific content-type header then you could use
when(
_.contentType.exists(m => m.equalsIgnoreCase(expectedContentType)),
tolerantJson(maxLength),
createBadResult("Wrong content type")
)
to create your own parser.

How to handle json payload in GET request Play 2.0 + Scala

I want to make a handler/controller for a GET request such as in ElasticSearch :
$ curl -XGET 'http://localhost:9200/twitter/tweet/_search?routing=kimchy' -d '{
"query": {
"filtered" : {
"query" : {
"query_string" : {
"query" : "some query string here"
}
},
"filter" : {
"term" : { "user" : "kimchy" }
}
}
}}
I read the documentation from http://www.playframework.org/documentation/2.0.4/ScalaJsonRequests but the example is based on POST request. I've tried on my own it appears that I can access to the body request with POST request. But, when I try with the GET request, my request.body is AnyContentAsEmpty.
Is there a way to handle the json from this request in Play 2.0 ?
I saw that there is no body semantic for GET : Payloads of HTTP Request Methods .
So maybe it's normal that there is no mechanism to deal with it through Play 2.0.
I believe you are confused on what can you expect on each type of request. To sum it up:
GET requests contain the payload in the URL, no request body is
added
POST requests add the payload to the request body
From the example you post it seems that you want to return a Json answer as a result from a GET request, which would make more sense.
That can be easily achieved by crafting the Json string and using the Ok(result).as("application/json") to set the MIME type of the response.
this is a sample question
Play's default body parser follows the HTTP spec, and ignores the message body for GET, DELETE, HEAD and OPTIONS methods. If you want to force it to parse a body, you can do that by explicitly passing a body parser, eg:
def delete = Action(parse.json) { implicit request =>
val json = request.body
val someProp = (json \ "someprop").as[String]
Ok(s"Prop is: $someProp")
}