PROC HTTP multipart POST request - http

I end up getting a 400 Bad request when I run the below SAS code
proc http
url = "&base_uri/repository/container/&containerAID/&version/assetgroup/&agaid/upload"
method="post"
in="../dataraw/ae.zip"
ct="multipart/form-data; boundary=--------------------------989556876368242564784888";
debug level = 3;
headers 'Authorization'="Bearer &ACCESS_TOKEN" ;
run;
Not sure why it won't go thru.

Related

Get network.request response headers in lua

I’m using network.request like this:
network.request( fullUrl, "POST", networkListener, params)
and receiving the response in my network listener as such:
local function networkListener( event )
if ( event.isError ) then
response = {};
else
response = json.decode(event.response);
end
end
I am receiving the body response of the request but I want to receive the request’s response headers as well. How can I achieve this?
Thanks a lot!
The documentation for network.request says:
network.request( url, method, listener [, params] )
listener (required)
Listener. The listener function invoked at various phases of the HTTP operation. This is passed a networkRequest event.
And the documentation for networkRequest links to event.responseHeaders, which gives this example:
-- Print the Content-Type header value for a response
local function networkListener( event )
print( "Content-Type of response is: " .. event.responseHeaders["Content-Type"] )
end

How to make correct HTTP Post request with ?key=value&key=value after the adress

I have a problem with doing by myself a http.post() request.
I want to perform API requests on NodeMCU based on ESP8266 with Lua language.
The first problem that i met was "Plain HTTP on HTTPS adress".
For now it says "bad token", so, it means that he didn't receive my post parameters.
How it need to be correct?
http.post("http://www.2level.1level/api.php","Content-Type: text/plain","token=mytokenhere&arg1=argumentforrequest",
function(code, data)
if (code < 0) then
print("HTTP request failed")
else
print(code, data)
end
end)
Usually i use GMod Lua for making requests. Code there will be easy:
http.Post("https://www.2level.1level/api.php",{token=mytokenhere,arg1=argumentforrequest},function(txt) end,function(txt) end)
http.Post on GMod Lua Wiki
==================
Update. I made my own code.
function ghttp.Post(url, parameters, onSuccess, onFailure, headers)
local add = ""
if parameters then
local temp = {}
for k,v in pairs(parameters) do
table.insert(temp,ghttp.encode(k).."="..ghttp.encode(v))
end
add = "?"..table.concat(temp, "&")
end
http.post(url..add,"Content-Type: application/json\r\n"..(headers or ""),"",function(code, data)
if (code < 0) then
if onFailure then onFailure() end
else
if onSuccess then onSuccess(code,data) end
end
end)
end
But now i have new problem:
Some API's request only HTTPs connection.
You didn't give us a URL to verify (would be hard because of the token, I know). So, untested the correct code would be like this:
http.post('https://www.2level.1level/api.php',
'Content-Type: application/json\r\n',
'{token=mytokenhere,arg1=argumentforrequest}',
function(code, data)
if (code < 0) then
print("HTTP request failed")
else
print(code, data)
end
end)
Make sure your {token=mytokenhere,arg1=argumentforrequest} is valid JSON by verifying with e.g. jsonlint.com.
In case you run into problems with HTTPS then this might be https://github.com/nodemcu/nodemcu-firmware/issues/1707.

How to send HTTP SOAP request to local Sonos device with NodeMCU?

How do I send a simple HTTP POST/GET SOAP request to my Sonos loudspeaker in Lua?
I have tried simple HTTP POST and GET requests with success, but I do not know where to start with SOAP requests.
Note: I am a newbie at this. I have never worked with a NodeMCU before nor have I programmed in Lua. I have experience in other languages though.
I know how to do it in C#, Java and PHP.
This works in Postman:
HTTP Headers:
SOAPAction:urn:schemas-upnp-org:service:AVTransport:1#Pause
Content-Type:text/xml; charset="utf-8"
Host:192.168.0.10:1400
BODY:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:Pause xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:Pause></s:Body></s:Envelope>
What I did is this and it does not work:
sendRequest("192.168.0.10")
function sendRequest(url)
print("Sending request to Sonos Playbar...")
sk = net.createConnection(net.TCP, 0)
sk:on("receive", function(sck, c) print(c) end )
sk:on("connection", function(sck, c)
print("\r\n\r\n\r\n")
-- HTTP 405: Method not allowed
-- sck:send("POST / HTTP/1.1\r\nHost: "..url..":1400\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n")
-- HTTP 500, UPnP 402: Invalid arguments
-- sck:send("POST /MediaRenderer/AVTransport/Control HTTP/1.1\r\nHost: "..url..":1400\r\nSOAPAction:urn:schemas-upnp-org:service:AVTransport:1#Pause\r\nConnection: keep-alive\r\n\r\nAccept: */*\r\n\r\n")
local content = nil;
content = "POST /MediaRenderer/AVTransport/Control\r\n"
content = content.."Host:192.168.0.10:1400\r\n"
content = content.."Content-Type:text/xml; charset=utf-8\r\n"
content = content.."SOAPAction:urn:schemas-upnp-org:service:AVTransport:1#Pause\r\n"
content = content.."\r\n"
-- SOAP Body
content = content.."<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\""
content = content.." s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
content = content.."<s:Body>"
content = content.."<u:Pause xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">"
content = content.."<InstanceID>0</InstanceID>"
content = content.."</u:Pause>"
content = content.."</s:Body>"
content = content.."</s:Envelope>"
-- SOAP Body End
print(content.."\r\n\r\n\r\n")
sck:send(content);
end)
sk:connect(1400, url)
end
I am getting this response of my Sonos player:
HTTP/1.1 500 Internal Server Error
CONTENT-LENGTH: 347
CONTENT-TYPE: text/xml; charset="utf-8"
EXT:
Server: Linux UPnP/1.0 Sonos/34.16-37101 (ZPS9)
Connection: close
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring>UPnPError</faultstring>
<detail>
<UPnPError xmlns="urn:schemas-upnp-org:control-1-0">
<errorCode>401</errorCode>
</UPnPError>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
What am I doing wrong? I copied and paste the text, basically. Maybe it is the order of headers? Maybe I am declaring the headers wrong or something?
I don't have a Sonos device to play with. Thus, this ain't a confirmed answer.
The string in your content variable is not a valid HTTP request. Sonos doesn't understand it as the error code 401 means "invalid action".
You need the separate HTTP headers with \r\n. An extra \r\n needs to be placed right before the HTTP body. Therefore, I'd expect that your content should be:
"POST http://192.168.0.10:1400/MediaRenderer/AVTransport/Control\r\n
SOAPAction:urn:schemas-upnp-org:service:AVTransport:1#Pause\r\n
Content-Type:text/xml; charset=\"utf-8\"\r\n
Host:192.168.0.10:1400\r\n\r\n
<s:Envelope xmlns:s=\"http://schemas.xml......"
Finally! I have it working! Below is the code to get it working:
sendRequest("192.168.0.10")
function sendRequest(url)
print("Sending request to Sonos Playbar...")
local content = nil;
content = "";
-- SOAP Body
content = content.."<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\""
content = content.." s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
content = content.."<s:Body>"
content = content.."<u:Pause xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\">"
content = content.."<InstanceID>0</InstanceID>"
content = content.."</u:Pause>"
content = content.."</s:Body>"
content = content.."</s:Envelope>"
-- SOAP Body End
http.post("http://"..url..":1400/MediaRenderer/AVTransport/Control",
'Content-Type: text/xml; charset="utf-8"\r\n'..
'Host:'..url..':1400\r\n'..
'SOAPAction:urn:schemas-upnp-org:service:AVTransport:1#Pause\r\n',
content, function(code, data)
if(code < 0) then
print("HTTP request failed with code "..code)
else
print(code, data)
end
end)
end

Send HttpRequest using post method with Ocaml Curl

I'm using Ocaml CURL to make http request to a server. I try to send it using the method post and I found this function (https://gist.github.com/zbroyar/1432555) :
let post ?(content_type = "text/html") url data =
let r,c = init_conn url in
Curl.set_post c true;
Curl.set_httpheader c [ "Content-Type: " ^ content_type ];
Curl.set_postfields c data;
Curl.set_postfieldsize c (String.length data);
Curl.perform c;
let rc = Curl.get_responsecode c in
Curl.cleanup c;
rc, (Buffer.contents r)
I understand that the value data contains the post values but in which form ? It should be "login=foo pass=bar" or "login=foo, pass=bar" ? Anyone has an idea ?
This is a POST request, it can send any kind of data using any form, that's why there is a Content-Type header to tell the server how to decode the data.
By default, this function will send HTML, if you want to use the form encoding, replace "text/html" with "application/x-www-form-urlencoded".

WebRequest problem, response before request-body

I'am using the WebRequest class in .net and POST data to a server which is responding with a Response.
The wierd thing is that its working when I started fiddler to analyze my network traffic, but without fiddler it isn't.
So i started to analyze the package which is sent to and from my computer with WireShark. With in this program its simple to follow the TCP-stream. So when I had fiddler on, I can see the correct Request-header/body is sent, and gets the Response-header/body. The strange part is when i dont use fiddler the Request-header is sent, then i´ve got the Response-header/body, and finally the request-body in the end of the TCP-stream.
Here is my code i've been elaborating:
string lcUrl = "http://XX.XX.XXX.XX";
// *** Establish the request
HttpWebRequest loHttp = (HttpWebRequest)WebRequest.Create(lcUrl);
string lcPostData = testdata;
loHttp.Method = "POST";
byte [] lbPostBuffer = System.Text.Encoding.GetEncoding(1252).GetBytes(lcPostData);
loHttp.ContentLength = lbPostBuffer.Length;
loHttp.Credentials = CredentialCache.DefaultCredentials;
//loHttp.SendChunked = true;
loHttp.ServicePoint.Expect100Continue = false;
Stream loPostData = loHttp.GetRequestStream();
loPostData.Write(lbPostBuffer, 0, lbPostBuffer.Length);
loPostData.Close();
HttpWebResponse loWebResponse = (HttpWebResponse)loHttp.GetResponse();
Encoding enc = System.Text.Encoding.GetEncoding(1252);
StreamReader loResponseStream = new StreamReader(loWebResponse.GetResponseStream(), enc);
string lcHtml = loResponseStream.ReadToEnd();
loWebResponse.Close();
loResponseStream.Close();
Please use following code. Seems that you have problems with time when underlying stream are send to remote server.
string lcUrl = "http://XX.XX.XXX.XX";
// *** Establish the request
HttpWebRequest loHttp = (HttpWebRequest)WebRequest.Create(lcUrl);
string lcPostData = testdata;
loHttp.Method = "POST";
byte[] lbPostBuffer = System.Text.Encoding.GetEncoding(1252).GetBytes(lcPostData);
loHttp.ContentLength = lbPostBuffer.Length;
loHttp.Credentials = CredentialCache.DefaultCredentials;
//loHttp.SendChunked = true;
loHttp.ServicePoint.Expect100Continue = false;
using (Stream loPostData = loHttp.GetRequestStream())
{
loPostData.Write(lbPostBuffer, 0, lbPostBuffer.Length);
}
string lcHtml;
using (HttpWebResponse loWebResponse = (HttpWebResponse)loHttp.GetResponse())
{
Encoding enc = System.Text.Encoding.GetEncoding(1252);
using (StreamReader loResponseStream = new StreamReader(loWebResponse.GetResponseStream(), enc))
{
lcHtml = loResponseStream.ReadToEnd();
}
}
// Perform processing of data here....
Also I could suggest you add following code in the app.config file for your application. This is helps when server returns response that not conforms with way how .NET handle HTTP request.
<configuration>
<system.net>
<settings>
<httpWebRequest
useUnsafeHeaderParsing="true"
/>
</settings>
</system.net>
</configuration>
I have a suspicion that the client is waiting for the "HTTP/1.1 100 continue" response from the server. This is how it works. When you are posting data to the server, sometimes the server might not be ready to accept the data just yet. For eg, it wants to authenticate the client first.
So, when you send a POST request, the client just sends the request headers, with an "Expect: 100-continue" appended.
POST /url HTTP/1.1
Server: Server-name/fqdn
Content-Length: 100
Expect: 100-continue
If the server is ready to receive the data it responds with:
HTTP/1.1 100 continue
Server: server-name/fqdn
Now, the client can send the data.
However if the server is not ready to receive the data, and wants to authenticate the client, it will respond with a different status code.
If you post your wireshark trace to pastebin.com I can verify, but I suspect this is what is happening.
The reason you dont see this in fiddler might be that fiddler is using HttpListener to listen to HTTP request, and HTTP listener hides the intermediate response like 100-continue from the app (in this case fiddler).

Resources