diff --git a/README.markdown b/README.markdown index 39cc52a..bd57151 100644 --- a/README.markdown +++ b/README.markdown @@ -32,6 +32,7 @@ curl -d "GET/hello" http://127.0.0.1:7379/ * URL-encoded parameters for binary data or slashes. For instance, `%2f` is decoded as `/` but not used as a command separator. * Logs, with a configurable verbosity. * Cross-origin XHR, if compiled with libevent2 (for `OPTIONS` support). +* File upload with PUT, if compiled with libevent2 (for `PUT` support). # Ideas, TODO... * Support PUT, DELETE, HEAD, OPTIONS? How? For which commands? @@ -41,7 +42,6 @@ curl -d "GET/hello" http://127.0.0.1:7379/ * Provide timeout (this needs to be added to hiredis first.) * Multi-server support, using consistent hashing. * Add WebSocket support (with which protocol?) -* Allow file upload with PUT? Saving a file in Redis using the `SET` command should be easy to do with cURL. * Send your ideas using the github tracker, on twitter [@yowgi](http://twitter.com/yowgi) or by mail to n.favrefelix@gmail.com. # HTTP error codes @@ -196,3 +196,51 @@ curl -v "http://127.0.0.1:7379/GET/big-file?type=application/pdf" [...] +# File upload (only with libevent 2) +Webdis supports file upload using HTTP PUT. The command URI is slightly different, as the last argument is taken from the HTTP body. +For example: instead of `/SET/key/value`, the URI becomes `/SET/key` and the value is the entirety of the body. This works for other commands such as LPUSH, etc. + +**Uploading a binary file to webdis**: +
+$ file redis-logo.png
+redis-logo.png: PNG image, 513 x 197, 8-bit/color RGBA, non-interlaced
+
+$ wc -c redis-logo.png
+16744 redis-logo.png
+
+$ curl -v --upload-file redis-logo.png http://127.0.0.1:7379/SET/logo
+[...]
+> PUT /SET/logo HTTP/1.1
+> User-Agent: curl/7.19.7 (x86_64-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
+> Host: 127.0.0.1:7379
+> Accept: */*
+> Content-Length: 16744
+> Expect: 100-continue
+>
+< HTTP/1.1 100 Continue
+< HTTP/1.1 200 OK
+< Content-Type: application/json
+< ETag: "0db1124cf79ffeb80aff6d199d5822f8"
+< Date: Sun, 09 Jan 2011 16:48:19 GMT
+< Content-Length: 19
+<
+{"SET":[true,"OK"]}
+
+$ curl -vs http://127.0.0.1:7379/GET/logo.png -o out.png
+> GET /GET/logo.png HTTP/1.1
+> User-Agent: curl/7.19.7 (x86_64-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15
+> Host: 127.0.0.1:7379
+> Accept: */*
+>
+< HTTP/1.1 200 OK
+< Content-Type: image/png
+< ETag: "1991df597267d70bf9066a7d11969da0"
+< Date: Sun, 09 Jan 2011 16:50:51 GMT
+< Content-Length: 16744
+
+$ md5sum redis-logo.png out.png
+1991df597267d70bf9066a7d11969da0  redis-logo.png
+1991df597267d70bf9066a7d11969da0  out.png
+
+ +The file was uploaded and re-downloaded properly: it has the same hash and the content-type was set properly thanks to the `.png` extension. diff --git a/cmd.c b/cmd.c index aedffcf..a02adac 100644 --- a/cmd.c +++ b/cmd.c @@ -88,7 +88,7 @@ decode_uri(const char *uri, size_t length, size_t *out_len, int always_decode_pl int cmd_run(struct server *s, struct evhttp_request *rq, - const char *uri, size_t uri_len) { + const char *uri, size_t uri_len, const char *body, size_t body_len) { char *qmark = strchr(uri, '?'); char *slash; @@ -108,6 +108,10 @@ cmd_run(struct server *s, struct evhttp_request *rq, p = strchr(p+1, '/'); } + if(body && body_len) { /* PUT request */ + param_count++; + } + cmd = cmd_new(rq, param_count); /* parse URI parameters */ @@ -169,6 +173,11 @@ cmd_run(struct server *s, struct evhttp_request *rq, cur_param++; } + if(body && body_len) { /* PUT request */ + cmd->argv[cur_param] = body; + cmd->argv_len[cur_param] = body_len; + } + /* push command to Redis. */ redisAsyncCommandArgv(s->ac, f_format, cmd, cmd->count, cmd->argv, cmd->argv_len); diff --git a/cmd.h b/cmd.h index 563f6cc..86d94dd 100644 --- a/cmd.h +++ b/cmd.h @@ -44,7 +44,8 @@ cmd_free(struct cmd *c); int cmd_run(struct server *s, struct evhttp_request *rq, - const char *uri, size_t uri_len); + const char *uri, size_t uri_len, + const char *body, size_t body_len); int cmd_select_format(struct cmd *cmd, const char *uri, size_t uri_len, formatting_fun *f_format); diff --git a/server.c b/server.c index a08dcb3..26f3d3a 100644 --- a/server.c +++ b/server.c @@ -132,15 +132,24 @@ on_request(struct evhttp_request *rq, void *ctx) { switch(rq->type) { case EVHTTP_REQ_GET: slog(s, WEBDIS_DEBUG, uri); - ret = cmd_run(s, rq, 1+uri, strlen(uri)-1); + ret = cmd_run(s, rq, 1+uri, strlen(uri)-1, NULL, 0); break; case EVHTTP_REQ_POST: slog(s, WEBDIS_DEBUG, uri); ret = cmd_run(s, rq, + (const char*)EVBUFFER_DATA(rq->input_buffer), + EVBUFFER_LENGTH(rq->input_buffer), NULL, 0); + break; + +#ifdef _EVENT2_HTTP_H_ + case EVHTTP_REQ_PUT: + slog(s, WEBDIS_DEBUG, uri); + ret = cmd_run(s, rq, 1+uri, strlen(uri)-1, (const char*)EVBUFFER_DATA(rq->input_buffer), EVBUFFER_LENGTH(rq->input_buffer)); break; +#endif default: slog(s, WEBDIS_DEBUG, "405");