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

Reply via email to