I write a little HTTPS client in C and I have a problem with the SSL_write function.
Three tests to illustrate my problem:
#define HEADERS1 "GET / HTTP/1.1\r\n"
#define HEADERS2 "Host: www.example.com\r\n"
#define HEADERS3 "User-Agent: OpenSSL\r\n"
#define HEADERS4 "\r\n"
#define HEADERS "GET / HTTP/1.1\r\nHost: www.example.com\r\nUser-Agent: OpenSSL\r\n\r\n"
Test 1:
SSL_write(ssl,HEADERS,strlen(HEADERS));
Success: The server correctly return the /index.html ressource with the HTTP/1.1 200 Code.
Test 2:
SSL_write(ssl,HEADERS1,strlen(HEADERS1));
SSL_write(ssl,HEADERS2,strlen(HEADERS2));
SSL_write(ssl,HEADERS3,strlen(HEADERS3));
SSL_write(ssl,HEADERS4,strlen(HEADERS4));
Failure: The server doesn't return anything. All SSL_write functions don't return ERROR but my application is locked on SSL_read because the destination server give no content... and no headers :(
Test 3:
SSL_write(ssl,HEADERS1,strlen(HEADERS1));
SSL_write(ssl,HEADERS2,strlen(HEADERS2));
SSL_write(ssl,HEADERS4,strlen(HEADERS4));
Success: The server correctly return the /index.html ressource with the HTTP/1.1 200 Code.
Is there a particular limitation on the number of times I can call SSL_write to send headers? Very strange...
Thanks you very much !
Ok, so my problem persits but I have more details:
IISS-SSL => All tests success.
Apache-SSL => All tests success.
Nginx-SSL => All tests success.
LightHTTPD-SSL => Test 2 failure.
I don't understand why only LightHTTPD don't understand my request...
For SSL_Write() operation, correct way should be after SSL_Write call , check on the message returned. If it is SSL_WANT_READ, then give some small amount of time for it to read.
Doing Continuous write operation with checking return value may be successful , but it is not safe, as you will not be sure of the data you wrote reached server and server read it completely.
This in turn may affect other SSL_write operations.
Related
This question already has answers here:
When does an HTTP 1.0 server close the connection?
(1 answer)
Detect end of HTTP request body
(6 answers)
HTTP header line break style
(3 answers)
Closed 3 years ago.
I'm trying to create a server in C sockets that will allow file uploads through HTTP. The problem I'm having is that I get a very good chunk of the HTTP content but then it just stops sending and begins hanging, perhaps waiting for a response or something? But since recv never hits 0 it never gets to my response. (not sure thats even the reason why).
I looked around on google but most answers are about receiving data and looping to receive more when I'm already doing that.
Heres the code:
fp = fopen("fileName", "a");
for(;;)
{
ret = recv(fd, buffer, BUFSIZE, 0);
if(ret == 0){
\\ Never gets here unless I cancel the web request manually (pressing x where refresh usually is)
printf("Finished recieving");
char* sendHeader = "HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: 8\n\nRecieved";
write(fd, sendHeader, strlen(sendHeader));
break;
}
if(ret == -1) {
printf("Error recieving");
break;
}
fprintf(fp, "%s", buffer);
}
fclose(fp);
Right now i'm just taking the file contents and appending it to a file.
The actual result's I'm getting is:
(using ... to abbreviate)
--WebKitFormBoundaryRMGRl...
Content-Dispotion: form-data; name="filetoUpload"; filename...;
Content-type: application/octet-stream
\n
Actual file contents
\n
--WebKitFormBoundaryRMGRl...
Content-Disposition: form data; name="submit"
Upload License
--WebKitFormBoundaryRMGRl...
Begins writing file contents again, writes about 10 lines, then hangs until I manually cancel request
When I print the byte values, i fill the buffer 2 times then the 3rd time it doesn't completely fill it and just hangs waiting?
Any ideas?
But since recv never hits 0 it never gets to my response ...
recv will return 0 if the client shuts down the connection. But the client will not shut down the connection since it want to receive the response (ok, it could shut down for writing then) and maybe wants to send more requests (HTTP persistent connection).
Instead you have to parse the HTTP request to figure out how much data the client will send in the body. The usual way to do this is by setting the Content-length header to the size of the body. If the size is not known up-front the client might use chunked transfer encoding though were each chunk is prefixed by its length (in hex).
Or in other words: if you are trying to implement HTTP then please make yourself familiar with the standard by studying it and not by making just assumptions. That's what standards are actually for.
I am trying to create simple FastCGI app written in C:
#include <fcgiapp.h>
#include <stdio.h>
int main()
{
int sockfd = FCGX_OpenSocket("127.0.0.1:9000", 1024);
FCGX_Request request;
FCGX_Init();
FCGX_InitRequest(&request, sockfd, 0);
while (FCGX_Accept_r(&request) == 0)
{
printf("Accepted\n");
FCGX_FPrintF(request.out, "Content-type: text/html\r\n\r\n<h1>Hello World!</h1>");
FCGX_Finish_r(&request);
}
}
It works fine - when i call it from browser, it displays page with "Hello World!" message.
The problem is that code inside a "while" works twice, i.e. I see following output in terminal:
[root#localhost example]$ ./hello
Accepted
Accepted
Why it prints "Accepted" twice per each request?
If I put real code here, e.g. query a DB, it will be executed twice as well.
What program are you using to make the web request? Some web clients may also request an e.g. favicon.ico file, which may account for the second request to the fcgi process:
127.0.0.1 - - [29/Aug/2015:16:02:11 +0000] "GET / HTTP/1.1" 200 32 "-" "..."
127.0.0.1 - - [29/Aug/2015:16:02:11 +0000] "GET /favicon.ico HTTP/1.1" 200 32 "http://127.0.0.1/" "..."
This could be determined by inspecting the webserver logs, or adding debugging to the C program to show the request parameters. Using just telnet to request GET / HTTP/1.0, I do not see a double hit for a forward-everything-to-fcgi webserver configuration using the nginx webserver.
My current project is a bare-metal webserver. For this I'm using no libraries, and programming directly onto the chip. What I'm trying to do right now is send a single piece of HTTP data:
HTTP/1.1 200 OK\r\n
Content-Length: 45\r\n
Content-Type: text/html\r\n
Server: microserver\r\n
Connection: close\r\n
\r\n
<!DOCTYPE html><html>Hello<br>world!<hr></html>
My server tries to go through the following steps:
Receive SYN
Send [SYN+ACK]
Receive ACK
Receive ACK containing HTTP GET
Send [ACK,PUSH,FIN] with HTTP data (this one changed a lot, I've tried sending ACK PUSH and FIN seperately (with the content in PUSH), tried [ACK+PUSH],FIN and ACK,[PUSH+FIN] as well.
Receive [ACK+FIN] <<--- Here's where it goes wrong, this one is never even sent, according to wireshark.
Send ACK.
As said, it goes wrong at step 6. every single time. No matter what combination of ACK, PUSH and FIN I use in step 5. When looking at it with wireshark all the SEQ and ACK numbers are correct.
My server is able to close connections once the [FIN+ACK] finally does get sent, which sometimes happens on sockets that are kept open by the browser synchronously.
Pcap file of what wireshark records: https://www.dropbox.com/s/062k9hkgkenaqij/httpdump.pcap with as filter: (tcp.dstport == 80 || tcp.srcport == 80) && (ip.dst == 169.254.100.100 || ip.src == 169.254.100.100)
I know there is a 4 year old very similar question, Building a webserver, client doesn't acknowledge HTTP 200 OK frame, but I've tried pretty much everything that was suggested in there, and it didn't seem to get me any further, so I'm out of ideas.
EDIT:
I have found the problem, after studying sections of wireshark captures for hours an end. Apparently the mistake was that I did not use data to calculate the TCP checksum... But well, found the solution.
I'm developing a system that tracks objects with a P(an)T(ilt)Z(oom) camera which can be controlled via HTTP requests. The C application I develop is supposed to receive position data of the tracked object and to send commands to the camera to control the pan and tilt angle. In addition to these commands the camera has to receive a session refresh command every 5 seconds. HTTP Digest Authorization has to be used for the connection.
I'm sending the HTTP request with libcurl. I figured already out that for digest auth one needs to use on and the same curl handle for all requests in this stackoverflow post.
For sending the session refresh command periodically I tried to use a thread which is just doing this:
while(1)
{
usleep(5000000);
sessionContinue(g_Config.cam_ip);
}
With sessionContinue looking like this:
CURLcode sessionContinue(char* url)
{
CURLcode res;
char requestURL[40];
char referer[47];
struct curl_slist *headers=NULL;
strcpy(requestURL , url);
strcat(requestURL, CAM_SESSION_CONTINUE);
strcpy(referer , "Referer: http://");
strcat(referer , url);
strcat(referer , CAM_MONITOR);
headers = curl_slist_append(headers,"Connection:keep-alive");
headers = curl_slist_append(headers, camCookie);
// In windows, this will init the winsock stuff
curl_global_init(CURL_GLOBAL_ALL);
curl_easy_reset(curl);
if(curl)
{
// First set the URL that is about to receive our POST. This URL can
//just as well be a https:// URL if that is what should receive the
//data.
curl_easy_setopt( curl , CURLOPT_URL , requestURL );
curl_easy_setopt( curl , CURLOPT_HTTPHEADER , headers );
curl_easy_setopt( curl , CURLOPT_HTTPGET , 1 );
curl_easy_setopt( curl , CURLOPT_USERNAME , "root" );
curl_easy_setopt( curl , CURLOPT_PASSWORD , "password" );
curl_easy_setopt( curl , CURLOPT_HTTPAUTH , CURLAUTH_BASIC | CURLAUTH_DIGEST );
// Perform the request, res will get the return code
res = curl_easy_perform(curl);
// Check for errors
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed # %s:%d : %s\n", curl_easy_strerror(res) , __FILE__ , __LINE__ );
}
return res;
}
The application always crashed with segmentation fault after executing curl_easy_perform(curl). So I read the libcurl tutorial again and now I know that using one curl handle in multiple threads is a no go.
What I tried then was to use a timer with SIGALRM to implement the periodic session refresh. This didn't change the problem with the crash at curl_easy_perform(curl). The strange thing is that the application doesn't crash when sending the normal command to control the pan and tilt position which uses the same curl handle. The only difference between session refresh and pan/tilt command is that session refresh uses GET and pan/tilt uses POST.
Are there any other possibilities to send pan/tilt commands continuously with a short pause every 5 seconds used to send the session refresh?
You have a long range of problems in one small program. Here's a few:
You might overflow one of those small fixed-size buffers with the dangerous unbounded C functions you use. Quite likely one of them is the reason for the segfault.
curl_global_init() is documented to be called once, you call it over and over again - this even without calling curl_global_cleanup() in between. You obviously call curl_easy_init() somewhere out of the function and you should move the global init there.
'referer' gets filled with data but is never used otherwise
Another advice is to use CURLOPT_ERRORBUFFER to get error messages in rather than curl_easy_strerror() as you may get some extra details then. And of course to set CURLOPT_VERBOSE while debugging the request to see that things look the way you want it.
Thanks for your comment Daniel Stenberg. I'm now calling curl_global_init() just once when the handle has been set up. referer wasn't really needed here, but I had forgotten to remove it before pasting the code here.
The reason for the segmentation fault was that the session refresh command and the commands for pan and tilt tried to use one and the same curl handle at the same time, which obviously can't really work. So the solution with the timer and SIGALRM wasn't the problem. The segmentation faults have been solved by adding a mutex lock to avoid concurrent accesses to the curl handle.
I've a CGI module written in C & for some condition I want to return HTTP error 400 from this module. The problem is - I don't know how to return HTTP error from the module.
Looks like the 'return(-1)' in my module, returns the 500 internal server error. I've tried returning 400 etc. but in vein. I've even tried "printf("Status:400");" before returning -1 (as suggested here: How to return a 500 HTTP status from a C++ CGI program ) but that didn't work.
Any advice on this would be appreciated.
Edit: [solved] I was able to return HTTP error code from the python module (which is called later by this C CGI module). So didn't get to try the suggestion mentioned in comments below. Thanks for offering help, though.
To return HTTP error 400 to the HTTP client, you have to write the HTTP status line to stdout, like this:
printf("Status: 400 Bad Request\n");
Ref: https://www.rfc-editor.org/rfc/rfc3875
The Status header field contains a 3-digit integer result code that
indicates the level of success of the script's attempt to handle the
request.
Status = "Status:" status-code SP reason-phrase NL
status-code = "200" | "302" | "400" | "501" | extension-code
extension-code = 3digit
reason-phrase = *TEXT
To return HTTP error code from your CGI script, you have to write it into stdout, such as:
#include <stdio.h>
int main()
{
printf("status: 400\n\n");
return 0;
}
Just the status: status-code\n\n is necessary.