I work on shttpd to make it handle the "100-continue" HTTP Header.
I work on last source, generated from the CVS checkout.
Whit this mail there are 3 patches.
To apply simple copy the files to the "src" directory, go into it and type:
patch -u -p2 < ./defs.h.patch
patch -u -p2 < ./shttpd.c.patch
patch -u -p2 < ./cgi.c.patch
Thank's to Leslie P. Polzer, shttpd hacker's and all people wich work on
Free Software!
Christian.
--- shttpd-1.42/src/cgi.c 2008-11-03 12:44:26.000000000 +0100
+++ shttpd-1.42-wip/src/cgi.c 2008-11-09 09:54:51.000000000 +0100
@@ -183,34 +183,38 @@
int
_shttpd_run_cgi(struct conn *c, const char *prog)
{
- struct env_block blk;
- char dir[FILENAME_MAX], *p;
- int ret, pair[2];
+ struct env_block blk;
+ char dir[FILENAME_MAX], *p;
+ int ret, pair[2];
- prepare_environment(c, prog, &blk);
- pair[0] = pair[1] = -1;
+ prepare_environment(c, prog, &blk);
+ pair[0] = pair[1] = -1;
- /* CGI must be executed in its own directory */
- (void) _shttpd_snprintf(dir, sizeof(dir), "%s", prog);
- for (p = dir + strlen(dir) - 1; p > dir; p--)
- if (*p == '/') {
- *p++ = '\0';
- break;
- }
-
- if (shttpd_socketpair(pair) != 0) {
- ret = -1;
- } else if (_shttpd_spawn_process(c,
- prog, blk.buf, blk.vars, pair[1], dir)) {
- ret = -1;
- (void) closesocket(pair[0]);
- (void) closesocket(pair[1]);
- } else {
- ret = 0;
- c->loc.chan.sock = pair[0];
- }
-
- return (ret);
+ /* CGI must be executed in its own directory */
+ (void) _shttpd_snprintf(dir, sizeof(dir), "%s", prog);
+ for (p = dir + strlen(dir) - 1; p > dir; p--)
+ if (*p == '/')
+ {
+ *p++ = '\0';
+ break;
+ }
+ if (shttpd_socketpair(pair) != 0)
+ {
+ ret = -1;
+ }
+ else if (_shttpd_spawn_process
+ (c, prog, blk.buf, blk.vars, pair[1], dir))
+ {
+ ret = -1;
+ (void) closesocket(pair[0]);
+ (void) closesocket(pair[1]);
+ }
+ else
+ {
+ ret = 0;
+ c->loc.chan.sock = pair[0];
+ }
+ return (ret);
}
void
--- shttpd-1.42/src/defs.h 2008-11-03 12:44:26.000000000 +0100
+++ shttpd-1.42-wip/src/defs.h 2008-11-09 10:36:51.000000000 +0100
@@ -123,6 +123,7 @@
union variant range; /* Range: */
union variant status; /* Status: */
union variant transenc; /* Transfer-Encoding: */
+ union variant expect; /* Expect: */
};
/* Must go after union variant definition */
@@ -183,6 +184,7 @@
#define FLAG_DONT_CLOSE 32
#define FLAG_ALWAYS_READY 64 /* File, dir, user_func */
#define FLAG_SUSPEND 128
+#define FLAG_100_CONTINUE 256 /* 100-continue multipart request */
};
struct worker {
--- shttpd-1.42/src/shttpd.c 2008-11-03 12:44:26.000000000 +0100
+++ shttpd-1.42-wip/src/shttpd.c 2008-11-10 13:15:42.000000000 +0100
@@ -46,11 +46,14 @@
{7, HDR_STRING, OFFSET(range), "Range: " },
{12, HDR_STRING, OFFSET(connection), "Connection: " },
{19, HDR_STRING, OFFSET(transenc), "Transfer-Encoding: " },
+ {8, HDR_STRING, OFFSET(expect), "Expect: " },
{0, HDR_INT, 0, NULL }
};
struct shttpd_ctx *init_ctx(const char *config_file, int argc, char *argv[]);
static void process_connection(struct conn *, int, int);
+static void read_stream(struct stream *stream);
+static void write_stream(struct stream *from, struct stream *to);
int
_shttpd_is_true(const char *str)
@@ -534,128 +537,253 @@
static void
decide_what_to_do(struct conn *c)
{
- char path[URI_MAX], buf[1024], *root;
- struct vec alias_uri, alias_path;
- struct stat st;
- int rc;
- struct registered_uri *ruri;
-
- DBG(("decide_what_to_do: [%s]", c->uri));
-
- if ((c->query = strchr(c->uri, '?')) != NULL)
- *c->query++ = '\0';
-
- _shttpd_url_decode(c->uri, strlen(c->uri), c->uri, strlen(c->uri) + 1);
- remove_double_dots(c->uri);
-
- root = c->ctx->options[OPT_ROOT];
- if (strlen(c->uri) + strlen(root) >= sizeof(path)) {
- _shttpd_send_server_error(c, 400, "URI is too long");
- return;
- }
-
- (void) _shttpd_snprintf(path, sizeof(path), "%s%s", root, c->uri);
-
- /* User may use the aliases - check URI for mount point */
- if (is_alias(c->ctx, c->uri, &alias_uri, &alias_path) != NULL) {
- (void) _shttpd_snprintf(path, sizeof(path), "%.*s%s",
- alias_path.len, alias_path.ptr, c->uri + alias_uri.len);
- DBG(("using alias %.*s -> %.*s", alias_uri.len, alias_uri.ptr,
- alias_path.len, alias_path.ptr));
- }
-
+ char path[URI_MAX], buf[1024], *root;
+ struct vec alias_uri, alias_path;
+ struct stat st;
+ int rc;
+ struct registered_uri *ruri;
+
+ DBG(("decide_what_to_do: [%s]", c->uri));
+
+ if ((c->query = strchr(c->uri, '?')) != NULL)
+ *c->query++ = '\0';
+
+ _shttpd_url_decode(c->uri, strlen(c->uri), c->uri, strlen(c->uri) + 1);
+ remove_double_dots(c->uri);
+
+ root = c->ctx->options[OPT_ROOT];
+
+ if (strlen(c->uri) + strlen(root) >= sizeof(path))
+ {
+ _shttpd_send_server_error(c, 400, "URI is too long");
+ /* STOP PROCESSING */
+ return;
+ }
+
+
+ (void) _shttpd_snprintf(path, sizeof(path), "%s%s", root, c->uri);
+
+ /* User may use the aliases - check URI for mount point */
+ if (is_alias(c->ctx, c->uri, &alias_uri, &alias_path) != NULL)
+ {
+ (void) _shttpd_snprintf(path, sizeof(path), "%.*s%s",
+ alias_path.len, alias_path.ptr, c->uri + alias_uri.len);
+ DBG(("using alias %.*s -> %.*s", alias_uri.len, alias_uri.ptr,
+ alias_path.len, alias_path.ptr));
+ }
#if !defined(NO_AUTH)
- if (_shttpd_check_authorization(c, path) != 1) {
- _shttpd_send_authorization_request(c);
- } else
+ /* AUTHORIZATION HANDLING ENABLED */
+ if (_shttpd_check_authorization(c, path) != 1)
+ {
+ _shttpd_send_authorization_request(c);
+ }
+ else
#endif /* NO_AUTH */
- if ((ruri = _shttpd_is_registered_uri(c->ctx, c->uri)) != NULL) {
- _shttpd_setup_embedded_stream(c,
- ruri->callback, ruri->callback_data);
- } else
- if (strstr(path, HTPASSWD)) {
- /* Do not allow to view passwords files */
- _shttpd_send_server_error(c, 403, "Forbidden");
- } else
+ if ((ruri = _shttpd_is_registered_uri(c->ctx, c->uri)) != NULL)
+ {
+ _shttpd_setup_embedded_stream
+ (c, ruri->callback, ruri->callback_data);
+ }
+ else if (strstr(path, HTPASSWD))
+ {
+ /* Do not allow to view passwords files */
+ _shttpd_send_server_error(c, 403, "Forbidden");
+ }
+ else
#if !defined(NO_AUTH)
- if ((c->method == METHOD_PUT || c->method == METHOD_DELETE) &&
- (c->ctx->options[OPT_AUTH_PUT] == NULL ||
- !_shttpd_is_authorized_for_put(c))) {
- _shttpd_send_authorization_request(c);
- } else
+ if ((c->method == METHOD_PUT || c->method == METHOD_DELETE) &&
+ (c->ctx->options[OPT_AUTH_PUT] == NULL ||
+ !_shttpd_is_authorized_for_put(c)))
+ {
+ _shttpd_send_authorization_request(c);
+ }
+ else
#endif /* NO_AUTH */
- if (c->method == METHOD_PUT) {
- c->status = _shttpd_stat(path, &st) == 0 ? 200 : 201;
+ if (c->method == METHOD_PUT)
+ {
+ c->status = _shttpd_stat(path, &st) == 0 ? 200 : 201;
+
+ if (c->ch.range.v_vec.len > 0)
+ {
+ _shttpd_send_server_error
+ (c, 501, "PUT Range Not Implemented");
+ }
+ else if ((rc = _shttpd_put_dir(path)) == 0)
+ {
+ _shttpd_send_server_error(c, 200, "OK");
+ }
+ else if (rc == -1)
+ {
+ _shttpd_send_server_error(c, 500, "PUT Directory Error");
+ }
+ else if (c->rem.content_len == 0)
+ {
+ _shttpd_send_server_error(c, 411, "Length Required");
+ }
+ else if ((c->loc.chan.fd = _shttpd_open
+ (path, O_WRONLY | O_BINARY | O_CREAT | O_NONBLOCK | O_TRUNC, 0644)) == -1)
+ {
+ _shttpd_send_server_error(c, 500, "PUT Error");
+ }
+ else
+ {
+ DBG(("PUT file [%s]", c->uri));
+ c->loc.io_class = &_shttpd_io_file;
+ c->loc.flags |= FLAG_W | FLAG_ALWAYS_READY ;
+ }
+ } /* if (c->method == METHOD_PUT) */
+
+ else if (c->method == METHOD_DELETE)
+ {
+ DBG(("DELETE [%s]", c->uri));
+ if (_shttpd_remove(path) == 0)
+ _shttpd_send_server_error(c, 200, "OK");
+ else
+ _shttpd_send_server_error(c, 500, "DELETE Error");
+ } /* if (c->method == METHOD_DELETE) */
+
+ else if (get_path_info(c, path, &st) != 0)
+ {
+ _shttpd_send_server_error(c, 404, "Not Found");
+ }
+ /* path exist and is readdable */
+ else if (S_ISDIR(st.st_mode) && path[strlen(path) - 1] != '/')
+ {
+ (void) _shttpd_snprintf
+ (buf, sizeof(buf), "Moved Permanently\r\nLocation: %s/", c->uri);
+ _shttpd_send_server_error(c, 301, buf);
+ }
+ else if (S_ISDIR(st.st_mode) &&
+ find_index_file(c, path, sizeof(path) - 1, &st) == -1 &&
+ !IS_TRUE(c->ctx, OPT_DIR_LIST))
+ {
+ _shttpd_send_server_error(c, 403, "Directory Listing Denied");
+ }
+ else if (S_ISDIR(st.st_mode) && IS_TRUE(c->ctx, OPT_DIR_LIST))
+ {
+ if ((c->loc.chan.dir.path = _shttpd_strdup(path)) != NULL)
+ _shttpd_get_dir(c);
+ else
+ _shttpd_send_server_error(c, 500, "GET Directory Error");
+ }
+ else if (S_ISDIR(st.st_mode) && !IS_TRUE(c->ctx, OPT_DIR_LIST))
+ {
+ _shttpd_send_server_error(c, 403, "Directory listing denied");
- if (c->ch.range.v_vec.len > 0) {
- _shttpd_send_server_error(c, 501,
- "PUT Range Not Implemented");
- } else if ((rc = _shttpd_put_dir(path)) == 0) {
- _shttpd_send_server_error(c, 200, "OK");
- } else if (rc == -1) {
- _shttpd_send_server_error(c, 500, "PUT Directory Error");
- } else if (c->rem.content_len == 0) {
- _shttpd_send_server_error(c, 411, "Length Required");
- } else if ((c->loc.chan.fd = _shttpd_open(path, O_WRONLY | O_BINARY |
- O_CREAT | O_NONBLOCK | O_TRUNC, 0644)) == -1) {
- _shttpd_send_server_error(c, 500, "PUT Error");
- } else {
- DBG(("PUT file [%s]", c->uri));
- c->loc.io_class = &_shttpd_io_file;
- c->loc.flags |= FLAG_W | FLAG_ALWAYS_READY ;
- }
- } else if (c->method == METHOD_DELETE) {
- DBG(("DELETE [%s]", c->uri));
- if (_shttpd_remove(path) == 0)
- _shttpd_send_server_error(c, 200, "OK");
- else
- _shttpd_send_server_error(c, 500, "DELETE Error");
- } else if (get_path_info(c, path, &st) != 0) {
- _shttpd_send_server_error(c, 404, "Not Found");
- } else if (S_ISDIR(st.st_mode) && path[strlen(path) - 1] != '/') {
- (void) _shttpd_snprintf(buf, sizeof(buf),
- "Moved Permanently\r\nLocation: %s/", c->uri);
- _shttpd_send_server_error(c, 301, buf);
- } else if (S_ISDIR(st.st_mode) &&
- find_index_file(c, path, sizeof(path) - 1, &st) == -1 &&
- !IS_TRUE(c->ctx, OPT_DIR_LIST)) {
- _shttpd_send_server_error(c, 403, "Directory Listing Denied");
- } else if (S_ISDIR(st.st_mode) && IS_TRUE(c->ctx, OPT_DIR_LIST)) {
- if ((c->loc.chan.dir.path = _shttpd_strdup(path)) != NULL)
- _shttpd_get_dir(c);
- else
- _shttpd_send_server_error(c, 500, "GET Directory Error");
- } else if (S_ISDIR(st.st_mode) && !IS_TRUE(c->ctx, OPT_DIR_LIST)) {
- _shttpd_send_server_error(c, 403, "Directory listing denied");
#if !defined(NO_CGI)
- } else if (_shttpd_match_extension(path,
- c->ctx->options[OPT_CGI_EXTENSIONS])) {
- if (c->method != METHOD_POST && c->method != METHOD_GET) {
- _shttpd_send_server_error(c, 501, "Bad method ");
- } else if ((_shttpd_run_cgi(c, path)) == -1) {
- _shttpd_send_server_error(c, 500, "Cannot exec CGI");
- } else {
- _shttpd_do_cgi(c);
- }
+ }
+ else if (_shttpd_match_extension
+ (path, c->ctx->options[OPT_CGI_EXTENSIONS]))
+ {
+ if (c->method != METHOD_POST && c->method != METHOD_GET)
+ {
+ _shttpd_send_server_error(c, 501, "Bad method ");
+ }
+ else
+ {
+ if(c->ch.expect.v_vec.ptr != NULL &&
+ strncmp(c->ch.expect.v_vec.ptr, "100-continue", 12) == 0)
+ {
+ int how_to_read;
+
+ if((how_to_read = c->ch.cl.v_int) == 0)
+ _shttpd_send_server_error(c, 411, "Length Required");
+ else
+ {
+ io_clear(&c->loc.io);
+
+ c->loc.io.head =
+ _shttpd_snprintf(c->loc.io.buf,
+ c->loc.io.size,
+ "HTTP/1.1 100 Continue\r\n\r\n");
+ c->loc.content_len = 0;
+ c->status = 100;
+ _shttpd_stop_stream(&c->loc);
+ write_stream(&c->loc, &c->rem);
+
+ /* "100 Continue" response was sent */
+
+
+ if(c->rem.io.size - c->rem.io.total <= how_to_read)
+ {
+ /* We need more space in the read buffer so we realloc it */
+ unsigned int nsize;
+ char *nbuf;
+
+ nsize =
+ (c->rem.io.size - c->rem.io.total) + how_to_read;
+
+ nbuf = realloc(c->rem.io.buf, nsize);
+
+ if(nbuf == NULL)
+ _shttpd_send_server_error(c, 500, "Internal Error");
+ }
+
+ /* Read remaining data from client */
+
+ do
+ {
+ int rbyte = 0, tot = 0;
+ while(rbyte < how_to_read)
+ {
+ rbyte = read(c->rem.chan.sock,
+ c->rem.io.buf + c->rem.io.total,
+ how_to_read);
+ if(rbyte <= 0)
+ break; /* Lost data ? */
+ tot += rbyte;
+ printf("%s:%s:%d: READING 100-continue. Buff: [%s]\n",
+ __FILE__, __FUNCTION__, __LINE__,
+ c->rem.io.buf + c->rem.io.total);
+ }
+ }
+ while(0);
+
+ } /* else */
+ } /* 100-continue */
+
+ if((_shttpd_run_cgi(c, path)) == -1)
+ {
+ _shttpd_send_server_error(c, 500, "Cannot exec CGI");
+ }
+ else
+ {
+ _shttpd_do_cgi(c);
+ }
+ }
#endif /* NO_CGI */
+
+
#if !defined(NO_SSI)
- } else if (_shttpd_match_extension(path,
- c->ctx->options[OPT_SSI_EXTENSIONS])) {
- if ((c->loc.chan.fd = _shttpd_open(path,
- O_RDONLY | O_BINARY, 0644)) == -1) {
- _shttpd_send_server_error(c, 500, "SSI open error");
- } else {
- _shttpd_do_ssi(c);
- }
-#endif /* NO_CGI */
- } else if (c->ch.ims.v_time && st.st_mtime <= c->ch.ims.v_time) {
- _shttpd_send_server_error(c, 304, "Not Modified");
- } else if ((c->loc.chan.fd = _shttpd_open(path,
- O_RDONLY | O_BINARY, 0644)) != -1) {
- _shttpd_get_file(c, &st);
- } else {
- _shttpd_send_server_error(c, 500, "Internal Error");
- }
+ }
+ else if (_shttpd_match_extension
+ (path, c->ctx->options[OPT_SSI_EXTENSIONS]))
+ {
+ if ((c->loc.chan.fd = _shttpd_open
+ (path, O_RDONLY | O_BINARY, 0644)) == -1)
+ {
+ _shttpd_send_server_error(c, 500, "SSI open error");
+ }
+ else
+ {
+ _shttpd_do_ssi(c);
+ }
+#endif /* NO_SSI */
+
+ }
+ else if (c->ch.ims.v_time && st.st_mtime <= c->ch.ims.v_time)
+ {
+ _shttpd_send_server_error(c, 304, "Not Modified");
+ }
+ else if ((c->loc.chan.fd = _shttpd_open
+ (path, O_RDONLY | O_BINARY, 0644)) != -1)
+ {
+ _shttpd_get_file(c, &st);
+ }
+ else
+ {
+ _shttpd_send_server_error(c, 500, "Internal Error");
+ }
}
static int
@@ -918,11 +1046,11 @@
n = stream->io_class->read(stream, io_space(&stream->io), len);
if (n > 0)
- io_inc_head(&stream->io, n);
+ io_inc_head(&stream->io, n);
else if (n == -1 && (ERRNO == EINTR || ERRNO == EWOULDBLOCK))
- n = n; /* Ignore EINTR and EAGAIN */
+ n = n; /* Ignore EINTR and EAGAIN */
else if (!(stream->flags & FLAG_DONT_CLOSE))
- _shttpd_stop_stream(stream);
+ _shttpd_stop_stream(stream);
DBG(("read_stream (%d %s): read %d/%d/%lu bytes (errno %d)",
stream->conn->rem.chan.sock,
@@ -960,11 +1088,11 @@
to->io_class ? to->io_class->name : "(null)", n, len, ERRNO));
if (n > 0)
- io_inc_tail(&from->io, n);
+ io_inc_tail(&from->io, n);
else if (n == -1 && (ERRNO == EINTR || ERRNO == EWOULDBLOCK))
- n = n; /* Ignore EINTR and EAGAIN */
+ n = n; /* Ignore EINTR and EAGAIN */
else if (!(to->flags & FLAG_DONT_CLOSE))
- _shttpd_stop_stream(to);
+ _shttpd_stop_stream(to);
}
@@ -1295,16 +1423,17 @@
return;;
/* Check for incoming connections on listener sockets */
- LL_FOREACH(&ctx->listeners, lp) {
- l = LL_ENTRY(lp, struct listener, link);
- if (!FD_ISSET(l->sock, &read_set))
- continue;
- do {
- sa.len = sizeof(sa.u.sin);
- if ((sock = accept(l->sock, &sa.u.sa, &sa.len)) != -1)
- handle_connected_socket(ctx,&sa,sock,l->is_ssl);
- } while (sock != -1);
- }
+ LL_FOREACH(&ctx->listeners, lp)
+ {
+ l = LL_ENTRY(lp, struct listener, link);
+ if (!FD_ISSET(l->sock, &read_set))
+ continue;
+ do {
+ sa.len = sizeof(sa.u.sin);
+ if ((sock = accept(l->sock, &sa.u.sa, &sa.len)) != -1)
+ handle_connected_socket(ctx,&sa,sock,l->is_ssl);
+ } while (sock != -1);
+ }
if (num_workers(ctx) == 1)
process_worker_sockets(first_worker(ctx), &read_set);
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
shttpd-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/shttpd-general