Location header wrong after HTTP POST? - http

please forgive me if I do something terribly wrong, I shall correct it at once).
I'm creating a RESTservice and I need the location of the created resources, both for testing purposes and for further development.
As far is I have understood from the rfc 2616, the location header that I get back after a HTTP POST should give me at link to the resource I have created.
14.30 Location
The Location response-header field is used to redirect the recipient
to a location other than the Request-URI for completion of the
request or identification of a new resource. For 201 (Created)
responses, the Location is that of the new resource which was created
by the request. For 3xx responses, the location SHOULD indicate the
server's preferred URI for automatic redirection to the resource. The
field value consists of a single absolute URI.
Location = "Location" ":" absoluteURI
An example is:
Location: http://www.w3.org/pub/WWW/People.html
link to rfc 2616
However, when I POST to create a new resource (for example with curl, but I tried different clients) as such:
curl -X POST -H "Content-Type: application/xml" -d "<?xml version=\"1.0\" encoding=\"UTF-8\"?><participant><first-name>Severinus</first-name><email>severinus#gmail.com</email></participant>" -v http://localhost:8080/VCTAserverFirstTest/services/participants
This is the header I get back:
upload completely sent off: 133 out of 133 bytes
HTTP/1.1 201 Created
Server Apache-Coyote/1.1 is not blacklisted
Server: Apache-Coyote/1.1
Location: http://localhost:8080/participants/1
Content-Length: 0
Date: Sat, 19 Apr 2014 16:07:31 GMT
Connection #0 to host localhost left intact
Here the Location is http://localhost:8080/participants/1 but the resources is in fact accessed on http://localhost:8080/VCTAserverFirstTest/services/participants/1
This is not what I expected. Do you need the server side code or is there an obvious answer to this?
Thanks
Lars
EDIT: Not a good answer for anybody else, but it was solved by using the resteasy framework.

Related

When can you have relative URLs on the request line of GET http requests?

I tried the following request:
GET index.htm HTTP/1.1
connection: close
host: example.com
content-length: 0
But earned a 400 Bad Request. Why? The server should be able to piece together the absolute URL: http://example.com/index.htm . Why does it complain? Do I need a referer header to use relative URLs on the request line?
Short answer
You can't use relative path because HTTP specification (RFC7230) requires the use of absolute path.
Explanation
If you just refer to HTTP specification, it easy to find out why your request got a 400 Bad Request response: it violates the specification.
RFC7230 defines that in your scenario, the request target must use what is called the origin-form that requires absolute path:
origin-form = absolute-path [ "?" query ]
For instance, the HTTP request for http://example.org/where?q=now would be:
GET /where?q=now HTTP/1.1
Host: example.org
If the path is empty, such as http://example.org the HTTP request would be:
GET / HTTP/1.1
Host: example.org
This is because the absolute path is required as explained in Section 5.3.1 as follows (emphasis mine):
When making a request directly to an origin server, other than a
CONNECT or server-wide OPTIONS request (as detailed below), a client
MUST send only the absolute path and query components of the target
URI as the request-target.
I think on this line GET index.htm HTTP/1.1 is missing an 'l' on index.html.
Hope that helps!
I found the answer: If the URL on the request line isn't absolute it must be an absolute path. This means that you can omit the protocol and host name, but never any part of the path. The following worked:
GET /index.htm HTTP/1.1
connection: close
host: example.com
content-length: 0

HTTP header 400 bad request response

I'm trying to test writing correct HTTP headers to understand
the syntax. Here I'm trying to PUT some text into httpbin.org/put and I expect the response body content to be the same.
PUT /HTTP/1.1
Host: httpbin.org
Accept-Language: en-us
Connection: Keep-Alive
Content-type: text/plain
Content-Length: 12
Hello jerome
However I'm getting the following bad request 400 response:
HTTP/1.1 400 Bad Request
Server: nginx
Date: Tue, 01 Mar 2016 12:34:02 GMT
Content-Type: text/html
Content-Length: 166
Connection: close
Response:
<html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx</center>
</body>
</html>
What syntactical errors have I done?
NOTE: newlines are \r\n not \n in the request.
Apparently the correct syntax goes like this for PUT:
PUT /put HTTP/1.1\r\n
Content-Length: 11\r\n
Content-Type: text/plain\r\n
Host: httpbin.org\r\n\r\n
hello lala\n
I believe I didn't say much on how I connected to httpbin.org; it was via sockets in C. So the connection was already established before sending the header + message.
You miss the destination url following the PUT verb, the first line must be:
PUT http://httpbin.org/ HTTP/1.1
This will probably also fail, you need one of their handler urls so they know what to reply with:
PUT http://httpbin.org/put HTTP/1.1
The general form of the first line, or Request Line, in an HTTP request is as follows:
<method> <path component of URL, or absolute URL> HTTP/<Version>\r\n
Where for your example, the method is PUT. Including an absolute URL (so, starting with http:// or https:// is only necessary when connecting to a proxy, because the proxy will then attempt to retrieve that URL, rather than attempt to serve a local resource (as found by the path component).
As presented, the only change you should have needed to make was ensuring there was a space between the / and HTTP/1.1. Otherwise, the path would be "/HTTP/1.1"... which would be a 404, if it weren't already a badly formed request. /HTTP/1.1 being interpreted as a path means the HTTP server that's parsing your request line doesn't find the protocol specifier (the HTTP/1.1 bit) before the terminating \r\n... and that's one example of how 400 response codes are born.
Hope that helped. Consult the HTTP 1.1 RFC (2616), section 5.1 for more information and the official definitions.

Getting 404 error if requesting a page through proxy, but 200 if connecting directly

I am developing an HTTP proxy in Java. I resend all the data from client to server without touching it, but for some URLs (for example this) server returns the 404 error if I am connecting through my proxy.
The requested URL uses Varnish caching, so it might be the root of problem. I cannot reconfigure it - it is not my.
If I request that URL directly with browser, the server returns 200 and the image is shown correctly.
I am stuck because I even do not know what to read and how to compose a search request.
Thanks a lot.
Fix the Host: header of the re-issued request. The request going out from the proxy either has no Host header or it is broken (or only X-Host exists). Also take note that the proxy application will execute its own DNS lookup and that might yield a different IP address than your local computer (where you issued the original request).
This works:
> curl -s -D - -o /dev/null http://212.25.95.152/w/w-200/1902047-41.jpg -H "Host: msc.wcdn.co.il"
HTTP/1.1 200 OK
Content-Type: image/jpeg
Cache-Control: max-age = 315360000
magicmarker: 1
Content-Length: 27922
Accept-Ranges: bytes
Date: Sun, 05 Jul 2015 00:52:08 GMT
X-Varnish: 2508753650 2474246958
Age: 67952
Via: 1.1 varnish
Connection: keep-alive
X-Cache: HIT

nginx - read custom header from upstream server

I am using nginx as a reverse proxy and trying to read a custom header from the response of an upstream server (Apache) without success. The Apache response is the following:
HTTP/1.0 200 OK
Date: Fri, 14 Sep 2012 20:18:29 GMT
Server: Apache/2.2.17 (Ubuntu)
X-Powered-By: PHP/5.3.5-1ubuntu7.10
Connection: close
Content-Type: application/json; charset=UTF-8
My-custom-header: 1
I want to read the value from My-custom-header and use it in a if clause:
location / {
// ...
// get My-custom-header value here
// ...
}
Is this possible?
It's not only possible, it's easy:
in nginx the response header values are available through a variable (one per header).
See http://wiki.nginx.org/HttpCoreModule#.24sent_http_HEADER for the details on those variables.
In your examle the variable would be $sent_http_My_custom_header.
I was facing the same issue. I tried both $http_my_custom_header and $sent_http_my_custom_header but it did not work for me.
Although solved this issue by using $upstream_http_my_custom_header.
When using NGINX as a proxy, there are four sets of headers:
client -> nginx: the client request headers
nginx -> upstream: the upstream request headers
upstream -> nginx: the upstream response headers
nginx -> client: the client response headers
You appear to be asking about the upstream response headers. Those are found in the $upstream_http_name variables.
However, take into account that any response headers are only set after the headers from the upstream server response have been received. Any if directives are run before sending the upstream request, and will not have access to any response headers! In other words, if directives are run after the client request has been received, before making the upstream request.
If you need to change how a response is handled, you can use a map directive however to set variables based on response headers, then use those variables in add_header (set client response headers), log_format or any othere directives that are active during the response phases (internally named the NGX_HTTP_CONTENT_PHASE and NGX_HTTP_LOG_PHASE phases). For more complex control you'll have to use a scripting add-on such as the Lua module (e.g. using a header_filter_by_lua_block directive).
To read or set individual headers, use:
from
to
type
read (variable)
write (directive)
client
nginx
request
$http_name
–
ngnix
upstream
request
–
proxy_set_header
upstream
nginx
response
$upstream_http_name
–
nginx
client
response
$sent_http_name
add_header
NGINX copies certain headers from client request to upstream request, and from upstream response to client response using various proxy_ directives, giving you options to omit or explicitly include headers for either direction. So if an upstream response header is only found in $upstream_http_name variables, then those headers were specifically not copied to the client response, and the set of available $sent_http_name variables will include any extra headers set by NGINX that are not present in the upstream response.
Use $http_MY_CUSTOM_HEADER
You can write some-thing like
set my_header $http_MY_CUSTOM_HEADER;
if($my_header != 'some-value') {
#do some thing;
}

Unable to test HTTP PUT-based file upload via Squid Proxy

I can upload a file to my Apache web server using Curl just fine:
echo "[$(date)] file contents." | curl -T - http://WEB-SERVER/upload/sample.put
However, if I put a Squid proxy server in between, then I am not able to:
echo "[$(date)] file contents." | curl -x http://SQUID-PROXY:3128 -T - http://WEB-SERVER/upload/sample.put
Curl reports the following error:
Note: This error response was in HTML format, but I've removed the tags for ease of reading.
ERROR: The requested URL could not be retrieved
ERROR
The requested URL could not be retrieved
While trying to retrieve the URL:
http://WEB-SERVER/upload/sample.put
The following error was encountered:
Unsupported Request Method and Protocol
Squid does not support all request methods for all access protocols.
For example, you can not POST a Gopher request.
Your cache administrator is root.
My squid.conf doesn't seem to be having any ACL/rule that should disallow based on the src or dst IP addresses, or the protocol, or the HTTP method... as I can do an HTTP POST just fine between the same client and the web server, with the same proxy sitting in between.
In case of the failing HTTP PUT case, to see the request and response traffic that was actually occurring, I placed a netcat process in between Curl and Squid, and this is what I saw:
Request:
PUT http://WEB-SERVER/upload/sample.put HTTP/1.1
User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
Host: WEB-SERVER
Pragma: no-cache
Accept: */*
Proxy-Connection: Keep-Alive
Transfer-Encoding: chunked
Expect: 100-continue
Response:
HTTP/1.0 501 Not Implemented
Server: squid/2.6.STABLE21
Date: Sun, 13 May 2012 02:11:39 GMT
Content-Type: text/html
Content-Length: 1078
Expires: Sun, 13 May 2012 02:11:39 GMT
X-Squid-Error: ERR_UNSUP_REQ 0
X-Cache: MISS from SQUID-PROXY-FQDN
X-Cache-Lookup: NONE from SQUID-PROXY-FQDN:3128
Via: 1.0 SQUID-PROXY-FQDN:3128 (squid/2.6.STABLE21)
Proxy-Connection: close
<SNIPPED the HTML error response already shown earlier above>
Note: I have anonymized the IP addresses and server names throughout for readability reasons.
Thanks to Amos Jeffries for answering this on squid-users forum. The issue is basically that Squid before version 3.1 does not implement HTTP 1.1 and thus rejects the chunked transfer encoding.

Resources