13

I am using a library from http://fastcgi.com/ in C++ application as a backend and nginx web-server as a front-end.

Posting files from HTML-form successfully and can see the temporary files on nginx server side. But I can't figure out how to access a body of multipart POST request using fastcgi_stdio. This is my HTML-form.

<html>
    <head>
        <title>Test Server</title>
        <script src="http://code.jquery.com/jquery.min.js"></script>
    </head>
    <body>
        <form id="upload-form" method="post" target="upload_target"   enctype="multipart/form-data" action="/upload">
            <input name="file" id="file" size="27" type="file" /><br />
            <input type="submit" name="action" value="Upload" /><br />
            <iframe id="upload_target" name="upload_target" src="" style="width:100%;height:100px;border:0px solid #fff;"></iframe>
        </form>
    </body>
</html>

My nginx conf file:

location /upload {

# Pass altered request body to this location
upload_pass @test;

# Store files to this directory
# The directory is hashed, subdirectories 0 1 2 3 4 5 6 7 8 9 should exist
upload_store /www/test;

# Allow uploaded files to be read only by user
upload_store_access user:rw group:r all:r;

# Set specified fields in request body
upload_set_form_field $upload_field_name.name $upload_file_name;
upload_set_form_field $upload_field_name.content_type "$upload_content_type";
upload_set_form_field $upload_field_name.path "$upload_tmp_path";

# Inform backend about hash and size of a file
upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";
upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";

upload_pass_form_field "^submit$|^description$";
upload_cleanup 400 404 499 500-505;
}

include fastcgi.conf;

# Pass altered request body to a backend
location @test {
        fastcgi_pass  localhost:8080
}

Now, how can handle/get the POST request body in my fastcgi c++ application and how to write it in proper file at the fastcgi app side ?

Is there any better fast module to achieve this?

Thank you.

user1495653
  • 133
  • 1
  • 1
  • 8

2 Answers2

12

You can access the POST body via the FCGI_stdin stream. For example, you can read from it one byte at a time using FCGI_getchar, which is a short form for FCGI_fgetc(FCGI_stdin). You can read larger chunks of data in a single call using FCGI_fread. All of this I found looking at the source. These sources often reference something called ”H&S”—this stands for "Harbison and Steele", the authors of the book C: A Reference Manual, and the numbers refer to chapters and sections of that book.

And by the way, it's called “stdio” for “STanDard Input/Output”. Not “studio”. The functions should mostly behave like their counterparts without FCGI_ prefixed. So for details, look at the man pages of getchar, fread and so on.

Once you have the bytes in your application, you can write them to file, either using normal stdio operations or files opened via FCGI_fopen. Note however that the input stream will not directly correspond to the content of an uploaded file. Instead, MIME encoding is used to transfer all form data, including files. You'll have to parse that stream if you want to access the file data.

Community
  • 1
  • 1
MvG
  • 57,380
  • 22
  • 148
  • 276
  • Thanks for the help. Will try this. But have one question nginx always buffers request bodies before opening a connection to FCGI. Is there any way to redirect that buffer directly to FCGI? or once the buffering completes, Send the file contents over the connection to the backend?(This will reduce the over head of parsing again, as Nginx is doing it.) Please correct me if my understanding is wrong. Thanks again. – user1495653 Oct 19 '12 at 07:43
  • @user1495653: I know near to nothing about Nginx, but I can see no reason for it to parse the data it buffers. I would assume that the HTTP server stops caring about the content once it has detected the end of the headers. So the methods I mentioned will probably already be reading from the buffer, and you'll be the first to actually parse that data. – MvG Oct 19 '12 at 08:27
  • OK. But again I would like to know if there is some module available in c/C++ which can give me requestHandler and some set of methods to access the request information using the handler? I guess there are some modules available in PHP, Ruby, etc. – user1495653 Oct 19 '12 at 09:32
  • @user1495653: The post I linked to has an answer suggesting [this question](http://stackoverflow.com/q/218089/1468366). [This question](http://stackoverflow.com/q/2265038/1468366) asked pretty much the same as well. There might be more. – MvG Oct 19 '12 at 12:17
5

Use this:

char * method = getenv("REQUEST_METHOD");
if (!strcmp(method, "POST")) {
    int ilen = atoi(getenv("CONTENT_LENGTH"));
    char *bufp = malloc(ilen);
    fread(bufp, ilen, 1, stdin);
    printf("The POST data is<P>%s\n", bufp);
    free(bufp);
}
B B
  • 3,922
  • 2
  • 18
  • 13