Project

General

Profile

Uploading file...

Added by Plug Gulp over 11 years ago

Hi,

I have following code to test uploading of a file:

<code class="cpp">
#include <Wt/WServer>
#include <Wt/WResource>
#include <Wt/Http/Response>

#include <fstream>

using namespace Wt;

class TestUpload : public Wt::WResource
{
    public:
        virtual ~TestUpload()
        {
            beingDeleted();
        }

    protected:
        virtual void handleRequest(const Wt::Http::Request &request, Wt::Http::Response &response)
        {
            Wt::log("TestUpload") << " Request Too Large? : " << request.tooLarge();
            Wt::log("TestUpload") << " Method             : " << request.method();
            Wt::log("TestUpload") << " Content Type       : " << request.contentType();
            Wt::log("TestUpload") << " Content Length     : " << request.contentLength();
            Wt::log("TestUpload") << " Content-Length     : " << request.headerValue("Content-Length");
            Wt::log("TestUpload") << " Expect             : " << request.headerValue("Expect");

            Http::UploadedFileMap fm = request.uploadedFiles();
            for_each(fm.begin(), fm.end(), [](Http::UploadedFileMap::value_type v) {
                            Wt::log("TestUpload") << " Filemap Key      : " << v.first;
                            Wt::log("TestUpload") << " File details     : ";
                            Wt::log("TestUpload") << "  Spool File Name : " << v.second.spoolFileName();
                            Wt::log("TestUpload") << "  Client File Name: " << v.second.clientFileName();
                            Wt::log("TestUpload") << "  Content type    : " << v.second.contentType();
                        }
                    );

            if(request.headerValue("Expect") == "100-continue") {
                // Should the response return status code 100 as per the HTTP standard? If yes, then the client actually receives status code 500!
                // Uncommenting the following line sends status code 500 to the client.
                //response.setStatus(100);
            } else {
                response.out() << "No 100-continue.\n";
            }

            std::ofstream f("srv.file", std::ios::out | std::ios::trunc | std::ios::binary);
            f << request.in().rdbuf();

            response.out() << "Done!\n";
        }
};

int main(int argc, char **argv)
{
    try {
        WServer server(argv[0]);

        server.setServerConfiguration(argc, argv);

        TestUpload tu;

        server.addResource(&tu, "/upload");

        if(server.start()) {
            WServer::waitForShutdown();
            server.stop();
        }
    } catch (WServer::Exception& e) {
        std::cerr << e.what() << std::endl;
    } catch (std::exception &e) {
        std::cerr << "exception: " << e.what() << std::endl;
    }
}
</code>

Here is the command I use to upload a file:

curl -i --upload-file upload.wt http://localhost/upload

And here is the log on the server side:

~/Wt/test13$ sudo ./upload.wt --docroot . --http-address 0.0.0.0
[2012-Aug-23 02:02:44.118462] 10341 - [info] "config: reading Wt config file: /etc/wt/wt_config.xml (location = './upload.wt')"
[2012-Aug-23 02:02:44.122273] 10341 - [info] "WServer/wthttp: initializing built-in wthttpd"
[2012-Aug-23 02:02:44.123853] 10341 - [info] "wthttp: started server: http://0.0.0.0:80"
[2012-Aug-23 02:02:55.990956] 10341 - [TestUpload] " Request Too Large? : 0"
[2012-Aug-23 02:02:55.991397] 10341 - [TestUpload] " Method             : PUT"
[2012-Aug-23 02:02:55.991592] 10341 - [TestUpload] " Content Type       : "
[2012-Aug-23 02:02:55.991800] 10341 - [TestUpload] " Content Length     : 487565"
[2012-Aug-23 02:02:55.991945] 10341 - [TestUpload] " Content-Length     : 487565"
[2012-Aug-23 02:02:55.992068] 10341 - [TestUpload] " Expect             : 100-continue"
127.0.0.1 - - [2012-Aug-23 02:02:55.997865] "PUT /upload HTTP/1.1" 200 6
[2012-Aug-23 02:02:55.998964] 10341 - [info] "WebRequest: took 1026.28ms"
^C[2012-Aug-23 02:03:18.700989] 10341 - [info] "WebController: shutdown: stopping sessions."
[2012-Aug-23 02:03:18.701277] 10341 - [info] "WServer/wthttp: Shutdown: stopping web server."

Looking at the log above, I am perplexed to see the "Expect" header with "100-continue" value. According to the HTTP standard, "100-continue" means:

_

The client SHOULD continue with its request. This interim response is used to inform the client that the initial part of the request has been received and has not yet been rejected by the server. The client SHOULD continue by sending the remainder of the request or, if the request has already been completed, ignore this response. The server MUST send a final response after the request has been completed.

_

But if I set the response status code to 100, the error code of 500 is received by the client! Here is the output on the client side:

~/Wt/test13$ curl -i --upload-file upload.wt http://localhost/upload
HTTP/1.1 500 Internal Server Error
Date: Thu, 23 Aug 2012 01:20:37 GMT
Content-Type: 
Transfer-Encoding: chunked

Done!
~/Wt/test13$ 

Why does the client receive the status code of 500? Also, why doesn't the "UploadedFileMap" of the request contain the details of the uploaded file?

Thanks and regards,

~Plug


Replies (8)

RE: Uploading file... - Added by Wim Dumon over 11 years ago

Hello Plug,

Did you compare with the resource found in WFileUpload.C? Can you spot any differences?

BR,

Wim.

RE: Uploading file... - Added by Plug Gulp over 11 years ago

@Wim Dumon

Did you compare with the resource found in WFileUpload.C?

Yes, I just did.

@Wim Dumon

Can you spot any differences?

Yes, I can. As far as I understand, the resource used by WFileUpload is expecting HTML and Javascript support on the client side? In the test scenario I am executing, the client does not have/require html and javascript. I am testing/evaluating a scenario where Wt can be used as a central core backend used by both Web and non-Web clients (communicating over HTTP).

Following is the verbose output of the cURL command. I posted the original query because, when the client expects a status code of 100 and the request handler does send a status code of 100 yet the client receives status code 500. And I am not able to understand why that is the case. If I understand why, then I will be able to take some remedial action in the request handler of my test code. I am using WHTTP server. Is the WHTTP server internally not able to cope with "Expect" header?

~/Wt/test13$ curl -v -i --upload-file upload.wt http://localhost/upload
* About to connect() to localhost port 80 (#0)
*   Trying 127.0.0.1... connected
> PUT /upload HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: localhost
> Accept: */*
> Content-Length: 599360
> Expect: 100-continue
> 
* Done waiting for 100-continue
* We are completely uploaded and fine
< HTTP/1.1 500 Internal Server Error
HTTP/1.1 500 Internal Server Error
< Date: Fri, 24 Aug 2012 08:31:26 GMT
Date: Fri, 24 Aug 2012 08:31:26 GMT
< Content-Type: 
Content-Type: 
< Transfer-Encoding: chunked
Transfer-Encoding: chunked

< 
Done!
* Connection #0 to host localhost left intact
* Closing connection #0
~/Wt/test13$ 

Thanks and regards,

~Plug

RE: Uploading file... - Added by Wim Dumon over 11 years ago

I didn't test your code, but I guess that our WResource expects you to set certain headers for the response which you don't. Maybe setMimeType()?

Probably fastest way to debug by stepping through the code and see why Wt decides to generate a 500 respone.

BR,

Wim.

RE: Uploading file... - Added by Plug Gulp over 11 years ago

@Wim Dumon

Probably fastest way to debug by stepping through the code and see why Wt decides to generate a 500 respone.

I did a quick search within Wt http code. Looks like built-in wthttp does not support all the HTTP status codes! Wthttp gobbles the status code set by the request handler that it does not understand and instead returns 500. Looks like an incomplete implementation of wthttp. The status codes supported by wthttp are as follows:

101, 200, 201, 202, 204, 206, 300, 301, 302, 303, 304, 307, 400, 401, 403, 404, 413, 416, 500, 501, 502, 503

The status codes listed under HTTP standard are as follows:

100, 101, 200, 201, 202, 203, 204, 205, 206, 300, 301, 302, 303, 304, 305, 306, 307, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415 416, 417, 500, 501, 502, 503, 504, 505

Regards,

~Plug

RE: Uploading file... - Added by Wim Dumon over 11 years ago

Hey Plug,

Hmm.. before we made the interface to HTTP replies public, we generated all status codes ourselves, and those are of course supported by wthttpd. Since the API allows now for extra status codes to be generated, we should probably extend the supported list.

On the other hand, a server can choose to ignore an Expect: 100-continue header, so my suggested work-around is to do that. I'm not 100% sure, but I also believe that at the point you arrive in the WResource, the entire request will already be read and spooled (to memory or disk, depending on its size), so by the rules of the same RFC you don't have to answer to the Expect header anymore.

BR,

Wim.

RE: Uploading file... - Added by Koen Deforche over 11 years ago

Hey Plug,

You can safely ignore the "Expect:" 100-continue. When the request arrives at the WResource, it is because it has been received entirely already, including the body.

As you can see, curl does not wait indefinitely for a "100 Continue" response, and that's because it shouldn't since a server is not obliged to interpret this header.

As Wim correctly suggests, you should simply ignore this header, and parse the body. In any case, sending a '100 Continue' after the request has been totally received is defeating the point of it.

Regards,

koen

RE: Uploading file... - Added by Claudio White about 6 years ago

I need that a user can upload files and used this example but i am wondering what has to be done on the client side?

There is no upload-Dialog in this example, how is/can "Wt::Http::Request &request" be filled when using normal URL call and not CURL?

I did not found such an example in forum and not in the documentation/tutorials.

I guess there must be an upload form before calling handleRequest....but where? Before addResource? And how Transfer files from the uploadForm so that handleRequest is called? I am confused...

I hope to find help here:-)

RE: Uploading file... - Added by Claudio White about 6 years ago

I did find it out using curl:

curl -X POST -d @Temp.txt http://myserver.com:8095/upload ---header "Content-Type:text/text"

With code snippet from Pulp Gulp and the curl command above i get following results:

[TestUpload] \" Request Too Large? : 0\"

[TestUpload] \" Method : POST\"

[TestUpload] \" Content Type : text/text\"

[TestUpload] \" Content Length : 1767\"

[TestUpload] \" Content-Length : 1767\"

[TestUpload] \" Expect : 100-continue\"

But i am wondering....why is fm empty (null)?

Wt::Http::UploadedFileMap fm = request.uploadedFiles();

request.uploadedFiles(); does not deliver my uploaded file.

Another try with the following is also null:

auto uf = request.getUploadedFile("d"); //tried also with "-d"

Btw.: I tried the other solution described in thread https://redmine.webtoolkit.eu/boards/2/topics/428?r=3782#message-3782 but same Problem, request.uploadedFiles() delivers nothing.

I thought i will get the Information about the Client file during the process when handleRequest is called?

What else i have to do that i will get the Information about the upload file into the request so that i can after then read the file content?

    (1-8/8)