Skip to content

Reading 'plain' argument from node.js request #2962

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
kris14an opened this issue Feb 13, 2017 · 10 comments
Closed

Reading 'plain' argument from node.js request #2962

kris14an opened this issue Feb 13, 2017 · 10 comments

Comments

@kris14an
Copy link

kris14an commented Feb 13, 2017

Basic Infos

Hardware

Hardware: NodeMCU
Core Version: Latest

Description

I'm trying to send JSON as POST data. Using Postman nodemcu read data perfectly. But when request from node.js 'server.arg("plain")' returns empty string.

Requests from wireshark below:

Debug Messages

POSTMAN reqest

POST /event HTTP/1.1
Host: 10.51.254.1
Connection: keep-alive
Content-Length: 32
Postman-Token: dadb7dfd-d44b-5a4a-7007-e7f9ac27824f
Cache-Control: no-cache
Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)                     Chrome/56.0.2924.87 Safari/537.36
Content-Type: application/json
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4

{"event":"ON","id":"2144993346"}

NODE.JS simple request

POST /event HTTP/1.1
Content-Type: application/json
host: 10.51.254.1
accept: application/json
content-length: 31
Connection: close

{"event":"ON","id":"2144993346"}

Sample node.js code using unirest

 unirest
.post('http://10.51.254.1/event')
.encoding('utf-8')
.type('json')
.send({"event":"ON","id":"2144993346"})
.end((res) => {
	console.log(res.statusCode);
});
@sidoh
Copy link
Contributor

sidoh commented Feb 14, 2017

Are you sure the body of the node.js request is what you posted? Judging from the capitalization of the headers, it seems like you might be reconstructing it, and not copy/pasting?

I've had better luck in Javascript sending a string-ified JSON blob. At least with jquery, even when setting Content-Type: application/json, tries to turn the body into a form-encoded string.

Maybe try something like:

 unirest
.post('http://10.51.254.1/event')
.encoding('utf-8')
.type('json')
.send(JSON.stringify({"event":"ON","id":"2144993346"}))
.end((res) => {
	console.log(res.statusCode);
});

?

@kris14an
Copy link
Author

Yes, i'm sure, those requests are copied from wireshark. I tried serialize object to JSON like in your example and they still are empty.

But, capitalization of the headers souldn't be a problem, that was repaired #2131

@sidoh
Copy link
Contributor

sidoh commented Feb 14, 2017

I didn't mean to suggest that capitalization was actually a problem, only that it seemed like it might indicate the request wasn't copy-pasted.

It seems like this is where the "plain" arg is getting set, and if I'm reading it right, it's only not set when the content type is application/x-www-form-urlencoded.

What do server.args() and server.argName(i) (for 0 <= i < server.args()) return?

@kris14an
Copy link
Author

i can't check it right now, but what I remember number of args was 0, (server.args() == 0), but i'll check later.

@kris14an
Copy link
Author

NodeMCU code

 ESP8266WebServer server;

 void setup() {
      server.on("/", HTTP_POST, []() {
          Serial.println(server.args());                  //0
          Serial.println(server.arg('plain'));          //empty string
          server.send(200, "text/plain", "ok");
     });
     server.begin();
}

void loop() {
     server.handleClient();
}

Node.js code same as before.

@sidoh
Copy link
Contributor

sidoh commented Feb 14, 2017

is server.arg('plain') going to do what you want? ' in C++ is for single characters, not string literals. Does server.arg("plain") (with double quotes) return what you want?

@kris14an
Copy link
Author

I didn't saw that mistake, but server.arg("plain") still is empty.

@kris14an kris14an changed the title Reading 'plain' argument Reading 'plain' argument from node.js request Feb 14, 2017
@noisemaker00
Copy link

noisemaker00 commented Jun 17, 2017

I have the same problem. I cannot read the POST data via server.arg("plain");

@oznu
Copy link

oznu commented Aug 5, 2017

I think the issue is when the ESP8266 looks for Content-Length header it is case sensitive.

Most of the node.js libraries will send the content-length header in lowercase because according to the RFC spec header case does not matter.

Using node/request as an example.

If I set the content-length header in lowercase, I just get an empty string when calling server.arg("plain");.

let body = JSON.stringify({targetMode: mode})
request.post(this.url, {
    body: body,
    headers: {
      'content-length': Buffer.byteLength(body)
    }
})

If I set the Content-Length header to use uppercase, all works as expected:

let body = JSON.stringify({targetMode: mode})
request.post(this.url, {
    body: body,
    headers: {
      'Content-Length': Buffer.byteLength(body)
    }
})

You can replicate it in curl as well.

This does not work:

curl -X POST -d '{"targetMode": "heat"}' -H "content-length: 21" http://esp8266.local

This does work:

curl -X POST -d '{"targetMode": "heat"}' -H "Content-Length: 21" http://esp8266.local

I'm not very familiar with c++/arduino yet, but it seems like the code at least attempting to ignore case here:

} else if (headerName.equalsIgnoreCase("Content-Length")){
  contentLength = headerValue.toInt();
} 

Edit: seems this is fixed in the latest pre-release as per the code above. I was using the latest stable release, 2.3.0 which has this issue.

@devyte
Copy link
Collaborator

devyte commented Sep 9, 2017

Closing per last Edit in last comment.

@devyte devyte closed this as completed Sep 9, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants