What is minimal HTTP 200 OK Connection close response for Nginx/lua/openresty. I have:
local sock, err = ngx.req.socket(true)
sock:send("HTTP/1.1 200 OK\\r\\nConnection: close\\r\\n\\r\\n")
and curl says:
curl: (52) Empty reply from server
In a case of no response body, you should probably use 204 No Content response code; "201 Created" may be an option as well for requests that create resources.
Also: replace each double slash with a single one, as you don't need to escape slash to generate CR LF sequence.
Related
I'm doing a coding exercise developing a HTTP server using Go's net/http library. The server is supposed to pass a series of tests in a Gitlab pipeline. I have no access to these tests and I can't see how they are implemented.
The problem is that one test for an expected HTTP 204 No Content response fails as follows:
Expected an empty response body "", got "\n"
The way I build the response in my code is:
// w is the http.ResponseWriter of the handler function.
w.WriteHeader(http.StatusNoContent)
w.Header().Del("Content-Type")
w.Write(nil)
I also tried w.Write(make([]byte, 0)) with the same result.
I'm testing it locally with curl but I can't really see the characters that are being returned in the body:
$ curl -i --header "Content-Type: application/x-www-form-urlencoded" --request POST --data "PARAMETER=1" host:9000/path
HTTP/1.1 204 No Content
Date: Thu, 10 Sep 2020 16:12:21 GMT
$
Is the net/http server actually returning a carriage return, and how can I prevent this?. Thank you.
Sorry, I was looking at the wrong piece of code. Because I don't have any details about the tests, I don't really know what exact case is being tested. The comments above are correct, just using w.WriteHeader(http.StatusNoContent) doesn't produce any carriage return in the body. No need to delete Content-Type. My mistake was that I was using http.Error(w, "", http.StatusNoContent) instead.
When using httr::GET, in certain queries it replaces % with safe representation %25, but in other queries it doesn't. I cannot find any rule that would make this happen.
I'm using httr 1.4.1
Sample query where % is replaced (notice the error code and that URL entered is not the same as in response object returned):
> httr::GET("jira.spring.io/rest/api/latest/search?jql=project=Spring%20Framework&startAt=0")
Response [https://jira.spring.io/rest/api/latest/search?jql=project=Spring%2520Framework&startAt=0]
Date: 2020-01-16 22:57
Status: 400
Content-Type: application/json;charset=UTF-8
Size: 196 B
Query where it is not replaced (no error, URL in response same as entered):
> httr::GET("issues.jenkins-ci.org/rest/api/latest/search?jql=project='WEBSITE'%20OR%20project='Infrastructure'&startAt=0")
Response [https://issues.jenkins-ci.org/rest/api/latest/search?jql=project='WEBSITE'%20OR%20project='Infrastructure'&startAt=0]
Date: 2020-01-16 23:02
Status: 200
Content-Type: application/json;charset=UTF-8
Size: 430 kB
What is going on? Is it a bug in httr? Or should I change some parameters in GET() call?
tldr; use HTTPS requests with jira.spring.io to avoid a broken protocol upgrade.
It's not an R/HTTR issue. It's the website. Compare the results of HTTP ("failing with mystery %25") and HTTPS ("succeeding"):
http://jira.spring.io/rest/api/latest/search?jql=project=Spring%20Framework&startAt=0
{"errorMessages":["Error in the JQL Query: The character '%' is a reserved JQL character. You must enclose it in a string or use the escape '\u0025' instead. (line 1, character 15)"],"errors":{}}
https://jira.spring.io/rest/api/latest/search?jql=project=Spring%20Framework&startAt=0
{"errorMessages":["Error in the JQL Query: Expecting either 'OR' or 'AND' but got 'Framework'. (line 1, character 16)"],"errors":{}}
There appears to be a 'malfunction' in the HTTP -> HTTPS redirect protocol upgrade, which has this response header:
Status Code: 301 Moved Permanently
Location: https://jira.spring.io/rest/api/latest/search?jql=project=Spring%252520Framework&startAt=0
^^^^^
Thus a solution is to use the HTTPS endpoint and avoid the strange target Location..
I use Nginx + lua module and body_filter_by_lua directive.
Nginx-lua docs said
When the Lua code may change the length of the response body, then it is required to always clear out the Content-Length response header (if any) in a header filter to enforce streaming output.
ngx.header.content_length = nil
Could it break keepalive connections?
Could it break requests on problematic channels?
How client will know that data is completely read from server?
Why Nginx does not forces Transfer-Encoding: chunked for this responses?
Update.
As a temporary solution i convert response to a chunked via
ngx.header['Content-Type'] = "text/html"
ngx.header['Content-Length'] = nil
ngx.header['Transfer-Encoding'] = 'chunked'
and in content-rewrite phase
-- Length of current chunk.
local hexlen = string.format("%x", #ngx.arg[1])
ngx.arg[1] = hexlen .. "\r\n" .. ngx.arg[1] .. "\r\n"
-- Last chunk. Send final sequence.
if (ngx.arg[2]) then
ngx.arg[1] = ngx.arg[1] .. "0\r\n\r\n"
end
Update 2.
Use ngx.location.capture!
I've just started working with the Quectel MC60 and I am having some issues:
About HTTP GET method, I make the following commands:
AT+QIFGCNT=0
AT+QICSGP=1,"my_apn"
AT+QIREGAPP
AT+QIACT
AT+QSSLCFG="https",1
AT+QHTTPURL=39,40
my_url_39_bytes_long
AT+QHTTPGET=60
AT+QHTTPREAD=30
AT+QIDEACT
When using the QCOM software, I make a script running all the above commands sequentially. When it comes to the AT+QHTTPREAD command, the response is always "+CME ERROR: 3822" (HTTP response failed). What can it be? I'm sure the HTTP server is working properly.
The answer is that it is necessary to configure the request header
AT+QIFGCNT=0
AT+QICSGP=1,"my_apn"
AT+QIREGAPP
AT+QIACT
AT+QHTTPURL=39,40
my_url_39_bytes_long
AT+QHTTPCFG="requestheader",1
AT+QHTTPPOST=77
GET path HTTP/1.1
User-Agent: Fiddler
Host: www.my_host.com
AT+QHTTPREAD=30
AT+QIDEACT
NOTE: in AT+HTTPPOST=77, 77 is the size of the POST message (last two \r\n are required and count)
NOTE2: after GET you're supposed to write the path to the url inserted in AT+QHTTPURL. For example, if you specified your URL as https://www.my_host.com/debug/main/port, your AT+HTTPPOST request should look like this (don't forget the last two \r\n):
GET /debug/main/port HTTP/1.1
User-Agent: Fiddler
Host: www.my_host.com
A bad HTTP client isn't escaping hash signs and is sending them to nginx, like so:
GET /foo/escaped#stuff
Instead of:
GET /foo/escaped%23stuff
This breaks my nginx configuration, since nginx strips the text after the # in the proxy_pass directive. How do I escape the hash sign?
Using return 200 "$request_uri"; does show me that nginx is reading it, so it seems like it's possible. Nginx, however, ignores it in location blocks, so I can't actually match it with anything.
You can use the below code to send unescaped HTTP GET requests in Python:
import socket
def get(host, port, uri):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
sock.send('GET {} HTTP/1.0\r\nHost: {}\r\n\r\n'.format(uri, host))
return sock.recv(1000)