C HTTP Proxy, the browser shows "waiting for" indefinetely - c

I have a hard time implementing a proxy server in C. It works for a few first webpages but then I get blocked while waiting for a new request.
Design:
Firefox -> Proxy -> Webserver --.
Firefox <- Proxy <- Webserver <-'
So each request is a round-trip from the browser to the proxy and the server and then back. Until the response from the request comes back, nothing should happen. I use no pipelining, threads or anything like that but rather only recv() and send() in a linear serial manner (for simplicity and intuition). I also don't close any sockets as I want to have a persistent connection.
I expect to be able and fetch one whole webpage including subrequested resources like css, img, js, etc..
In my implementation I manage to fetch a few first requests for a webpage. Then it hangs at step 1.
Implementation:
puts("Waiting for user to connect..");
int sock_user = accept(sock, (struct sockaddr*)NULL, NULL);
int sock_host = -1;
printf("User connected.\n");
// Accept requests
while(1){
http_request req;
http_response resp;
// 1. Client ==> Proxy Server
http_parse_request(sock_user, &req); // uses recv()
// 2. Client Proxy ==> Server
if (sock_host < 0)
sock_host = proxy_connect_host(req.header->host);
write(sock_host, req.header->raw_data, req.header->raw_size);
// 3. Client Proxy <== Server
http_parse_response(sock_host, &resp); // uses recv()
// 4. Client <== Proxy Server
write(sock_user, resp.header->raw_data, resp.header->raw_size);
write(sock_user, resp.body ->first_block->data, resp.body ->first_block->size);
}
Log:
---- ......................................... ----
---- after succesfully responded to 4 requests ----
Client ==> Proxy Server
Received 389
Client Proxy ==> Server
Sending.. 389
Sent 389
Client Proxy <== Server
Got header 312
Got body 1437
Response total 1749
Client <== Proxy Server
Sending header.. 312
Sent 312
Sending body.. 1437
Sent 1437
Client ==> Proxy Server
---- Hangs/blocks here ----
Firebug:
Wireshark:
I have no intuition as to what the reason for that block is and I have spent a whole week trying to resolve this problem without a breakthrough.
Among things tried to resolve problem:
Sending some extra CRLF for each response body
Checked the return value from each recv() and send(). (in the log above,
the values getting printed are the return values from recv and
send)
I hope someone could give at least some direction as to how to troubleshoot this or my brain will soon explode :)

You have to be very careful not to read too much data. E.g. make sure that:
header is read only up to the double CRLF; store extra data and sent them with the body
sending of body starts not before the server has sent the complete header (does not apply to this GET case but is important for POST or CONNECT)
there are received and sent only Content-Length bytes from the body
This applies to both the client -> proxy request and the server -> proxy response.
Your sample code stays in an endless loop (while (1) ...). How do you abort this? Do you honor the "Proxy-Connection" header?

Related

HTTP response message generated by server is not being recognized as a response

I'm programming a simple web server in C. The HTTP message the server generates is stored in a buffer and sent (via send()) as follows:
Scenario 1:
"200 OK\nContent-Type: text/html\nContent-Length: " + resource size in bytes + "\r\n\n"
where the resource size in bytes is converted to a char array using snprintf and then concatenated into the string.
Scenario 2:
"HTTP1.1 404 Not Found\r\nContent-Length: 0\r\n\n"
Scenario 3:
"HTTP1.1 405 Method Not Allowed\r\nAllow: GET, HEAD\r\n"
These are the headers, they are sent beforehand. The message body is sent afterwards as follows:
char resource[length];
int numRead;
while ( (numRead= read(filefd, resource, length)) > 0 )
send(client, resource, length, 0);
When I use wireshark, it doesn't recognize it as an HTTP response. When I use firefox, the web page continues loading until I shut down the server, at which point it displays the HTTP response instead of a webpage (index.html):
image
Do I have to encode the message before sending? Or is there something wrong with my message format?
There are many errors here which suggest that you just made up your own version of HTTP instead of reading the standard. Please refer to the standard for all the details if you want to implement HTTP.
In short:
"200 OK\nContent-Type: text/html\nContent-Length: " + resource size in bytes + "\r\n\n"
It should be HTTP/1.1 200 OK... and not just 200 OK.... All line ends must be \r\n and not \n and there must be a single \r\n at the end of the HTTP header.
"HTTP1.1 404 Not Found\r\nContent-Length: 0\r\n\n"
"HTTP1.1 405 Method Not Allowed\r\nAllow: GET, HEAD\r\n"
It should be HTTP/1.1 not HTTP1.1. And then all the other problems.
Again, if you really want to implement your own HTTP stack then study the standard. It is far more complex than you might think. Just because HTTP is a text based protocol does not mean that it is simple nor that any text is a correct HTTP message. Additionally implementations are tolerant in different ways, so just because it works with one client (i.e. browser) does not mean it is correct and that it will work with a different client too.

Kong: Client Closing keep-alive connections

I am writing a custom plugin for kong. The plugin will transform request/response in accordance with my server. I am getting [info] 27#0: *588 client <x> closed keepalive connection.
After some debugging, I found that the error occurs whenever I set the
ngx.arg[1] with my transformed response. I have followed the existing response-transformer plugin provided by kong.
This is the body of the kong body_filter function:
local ctx = ngx.ctx
local chunk, eof = ngx.arg[1], ngx.arg[2]
ctx.rt_body_chunks = ctx.rt_body_chunks or {}
ctx.rt_body_chunk_number = ctx.rt_body_chunk_number or 1
if eof then
local someChunks = concat(ctx.rt_body_chunks)
local aBody = responseTransformer.transform(theConf, someChunks)
aBody = unEscapeString(aBody)
ngx.arg[1] = aBody or someChunks
else
ctx.rt_body_chunks[ctx.rt_body_chunk_number] = chunk
ctx.rt_body_chunk_number = ctx.rt_body_chunk_number + 1
ngx.arg[1] = nil
end
I ran the same plugin with a local dummy server. It worked properly. But when I proxied to my actual server, I got the closed keepalive connection error.
From kong logs, I can see that the response got transformed properly.
Using curl, I get about half the body of the response.
Found the cause. The server was sending Content-Length header. During rewrite of body this remained unchanged. So, connection was being closed before the full content was being delivered.
To solve this, I had to clear the Content-Length header in the header_filter function:
kong.response.clear_header("Content-Length")

ActiveMQ 5.15.4 STOMP 1.2 behavior unexpected

Below I am trying to execute the STOMP commands via netcat and when I try to get a receipt for the first message I receive the 2nd message unexpectedly (a RECEIPT and MESSAGE) when I only expected a RECEIPT to come back from the server. The below commands are executed with 4 messages on the queue. Please advise.
Sent to server
CONNECT
login: sender_receiver
passcode:sender_receiver
accept-version:1.2
^#
From the server
CONNECTED
server:ActiveMQ/5.15.4
heart-beat:0,0
session:ID:centos7-42009-1529845487133-3:5
version:1.2
Sent to the server
SUBSCIBE
destination:/queue/queueName
activemq.prefetchSize:1
ack:client
id:12345
^#
Received from server
MESSAGE
content-length:9
expires:0
destination:/queue/queueName
ack:ID\ccentos7-42009-1529845487133-14\c1
subscription:12345
priority:4
redelivered:true
message-id:ID\ccentos7-42009-1529845487133-3\c4\c-1\c1\c1
persistent:true
timestamp:1529845914578
message 0
Sent to server
ACK
receipt:ack_id_receipt
id:ID\ccentos7-42009-1529845487133-14\c1
^#
Received from server
RECEIPT
receipt-id:ack_id_receipt
MESSAGE
content-length:9
expires:0
destination:/queue/queueName
ack:ID\ccentos7-42009-1529845487133-16\c2
subscription:12345
priority:4
message-id:ID\ccentos7-42009-1529845487133-3\c10\c-1\c1\c2
persistent:true
timestamp:1529863616319
message 1

What is a proper HTTP status code that server returns when it limits total number of connections?

I have made a simple HTTP server that listens to socket connections. The server code limits total number of connections that it can hold simultaneously.
So, I have these lines:
do {
new_fd = accept(lfd, NULL, NULL);
nfds += 1;
...
if(nfds + 1 > ntotal){ // connection limit exceeded
set_headers( new_fd, /* HTTP status code here */ );
/* close socket after error had been sent */
}
}while(1);
In this situation I'm interested with HTTP status code that server should send before closing socket.
From this link, it appears 503 is the appropriate HTTP status code to send for an overloaded server.
10.5.4 503 Service Unavailable
The server is currently unable to handle the request due to a
temporary overloading or maintenance of the server. The implication is
that this is a temporary condition which will be alleviated after some
delay. If known, the length of the delay MAY be indicated in a
Retry-After header. If no Retry-After is given, the client SHOULD
handle the response as it would for a 500 response.
Note: The existence of the 503 status code does not imply that a
server must use it when becoming overloaded. Some servers may wish
to simply refuse the connection.
(bold emphasis mine)

mg_send_response_line() in mongoose not working

I am trying to develop a server application using mongoose C library. In the initial stage of the my try, I am stuck at sending a response for an HTTP request. I am trying to send a simple response of status 200 using following line of code:
mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *");
printf("Response sent...\n");
But the response is not received to the client(Postman or web-browser).
There is no error, and even the printf line of Response sent is printed.
As against to this, following lines are getting executed successfully:
mg_http_send_error(nc,404, "Fatal Error!"); // I get this error at client side.
The basic simplest_web_server also works fine. Why is my single line of code sending response failing. I am not able to understand/ debug this.
Regards,
Neeraj.
The issue is that there is no content length or transfer encoding specified for the HTTP response and the server does not close the connection so the client hangs waiting for the response.
If you look through the source code, you will see that in mg_http_send_error(), the MG_F_SEND_AND_CLOSE flag is set but it is not set within mg_send_response_line() (though, like you, I assumed that this would be handled by the function).
To fix the issue in your context,
mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *");
printf("Response sent...\n");
nc->flag |= MG_F_SEND_AND_CLOSE;

Resources