diff options
author | LAN-TW <lantw44@gmail.com> | 2014-01-15 06:33:03 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2014-01-15 06:33:03 +0800 |
commit | 01b4949633b43d88f3ee319491db73b93987247a (patch) | |
tree | 4bf5fe00218a60dfc163071f56d2143dab579a6e | |
parent | 9d8903de3ca42b6daf2b716f2c1683430ca5e2b9 (diff) | |
download | sp2013-01b4949633b43d88f3ee319491db73b93987247a.tar.gz sp2013-01b4949633b43d88f3ee319491db73b93987247a.tar.zst sp2013-01b4949633b43d88f3ee319491db73b93987247a.zip |
HW4: 基本 CGI 功能已經可以使用,但尚未完整測試
-rw-r--r-- | hw4/chttpd/chttpd-conn.c | 171 | ||||
-rw-r--r-- | hw4/l4basic/l4str.c | 2 |
2 files changed, 167 insertions, 6 deletions
diff --git a/hw4/chttpd/chttpd-conn.c b/hw4/chttpd/chttpd-conn.c index 41e1c79..b123a87 100644 --- a/hw4/chttpd/chttpd-conn.c +++ b/hw4/chttpd/chttpd-conn.c @@ -21,8 +21,11 @@ #include <signal.h> #include <stdlib.h> #include <stdio.h> +#include <sys/select.h> #include <sys/stat.h> +#include <sys/time.h> #include <sys/types.h> +#include <sys/wait.h> #include <unistd.h> #define NL "\015\012" @@ -59,7 +62,7 @@ static char* http_status_msg[] = { "[403]</a></p>" "</body></html>" NL, [HTTP_STATUS_404_NOT_FOUND] = - "\n<html><head><title>400 Not Found</title></head>" NL + "\n<html><head><title>404 Not Found</title></head>" NL "<body><p>Request resource cannot be found on this server." NL "<a href=\"http://tools.ietf.org/search/rfc2616#section-10.4.5\">" "[404]</a></p>" @@ -135,7 +138,7 @@ static inline void internal_setenv (LbsStrv* strv, char* str_no_null = lbs_strv_get_str_not_null_terminated (strv, i); char* str_equ_loc = memchr (str_no_null, '=', slen); if (str_equ_loc != NULL && var_len < slen && - strncmp (str_no_null, var, var_len)) { + strncmp (str_no_null, var, var_len) == 0) { str_wrapper = lbs_strv_get_str_wrapper (strv, i); equ_loc = str_equ_loc; break; @@ -180,7 +183,8 @@ void* chttpd_conn_http (void* ptr_to_ChttpdConn) { char errmsg[ERRLEN]; LbsArray* hdr_buf = lbs_array_new (sizeof (char)); LbsArray* out_buf = lbs_array_new (sizeof (char)); - size_t data_offset; + ssize_t data_offset; + ssize_t data_count; while (true) { ssize_t r = read (connfd, conn->buf, CHTTPD_CONN_BUF_SIZE); @@ -203,6 +207,7 @@ void* chttpd_conn_http (void* ptr_to_ChttpdConn) { lbs_array_append_mass (hdr_buf, conn->buf, data_offset); lbs_array_append_data (hdr_buf, &(char){ '\0' }); data_offset += 4; + data_count = r - data_offset; break; } else { lbs_array_append_mass (hdr_buf, conn->buf, r); @@ -243,8 +248,13 @@ void* chttpd_conn_http (void* ptr_to_ChttpdConn) { char* request_method = ma1; char* request_uri = ma2 + 1; char* server_protocol = (ma3 == NULL) ? "" : ma3; - char* query_string = strtok_r (request_uri, "?", &tokstore); - query_string = (query_string == NULL) ? "" : query_string; + char* query_string = strchr (request_uri, '?'); + if (query_string != NULL) { + *query_string = '\0'; + query_string++; + } else { + query_string = ""; + } #ifdef SPHW_RESTRICTION for (char* p = request_uri; *p != '\0'; p++) { @@ -333,6 +343,9 @@ void* chttpd_conn_http (void* ptr_to_ChttpdConn) { int statfd; struct stat st; if (read (pipe_exec[0], &errnum, sizeof (int)) > 0) { + close (pipe_in[1]); + close (pipe_out[0]); + close (pipe_exec[0]); switch (errnum) { case ENOENT: // File not found chttpd_log_write (hlog, "[%4llu] 404 Not Found", id); @@ -406,6 +419,7 @@ void* chttpd_conn_http (void* ptr_to_ChttpdConn) { goto http_exit; } } + close (pipe_exec[0]); } else { close (pipe_in[1]); while (dup2 (pipe_in[0], 0) < 0); @@ -426,8 +440,155 @@ void* chttpd_conn_http (void* ptr_to_ChttpdConn) { _exit (127); } + pthread_rwlock_wrlock (&conn->lock); + conn->pid = pid; + pthread_rwlock_unlock (&conn->lock); + + int nfds = 1, mfds = connfd > pipe_out[0] ? (connfd + 1) : (pipe_out[0] + 1); + fd_set setin, setout; + FD_ZERO (&setin); +// FD_SET (connfd, &setin); XXX Some data may be sent from the client + FD_SET (pipe_out[0], &setin); + while (nfds > 0 || data_count > 0) { + if (data_count > 0) { + size_t r = lbs_posix_write_all ( + pipe_in[1], conn->buf + data_offset, data_count); + if (r < data_count) { + int errno_backup = errno; + chttpd_log_write (hlog, "[%4llu] 500 Internal Server Error: " + "write: %s", id, get_errmsg (errno, errmsg, ERRLEN)); + if (errno_backup == EPIPE) { + lbs_posix_write_all (connfd, + http_status_hdr[HTTP_STATUS_500_INTERNAL_SERVER_ERROR], 0); + lbs_posix_write_all (connfd, + "Content-Type: text/html" NL NL, 0); + lbs_posix_write_all (connfd, + "\n<html><head><title>500 Internal Server Error</title></head>" NL + "<body><p>Pipes closed the by CGI program." NL + "<a href=\"http://tools.ietf.org/search/rfc2616#section-10.5.1\">" + "[500]</a></p></body></html>" NL, 0); + } else { + http_status_write (connfd, HTTP_STATUS_500_INTERNAL_SERVER_ERROR); + } + close (pipe_in[1]); + close (pipe_out[0]); + goto http_exit; + } + data_count = 0; + data_offset = 0; + } + + if (nfds <= 0) { + continue; + } + + setout = setin; + select (mfds, &setout, NULL, NULL, NULL); + + if (FD_ISSET (connfd, &setout)) { + data_count = read (connfd, conn->buf, CHTTPD_CONN_BUF_SIZE); + if (data_count == 0 || + (data_count < 0 && (errno != EINTR && errno != EAGAIN))) { + nfds--; + FD_CLR (connfd, &setin); + } + } + if (FD_ISSET (pipe_out[0], &setout)) { + ssize_t r = read (pipe_out[0], conn->buf, CHTTPD_CONN_BUF_SIZE); + if (r > 0) { + lbs_array_append_mass (out_buf, conn->buf, r); + } else if (r == 0 || (r < 0 && (errno != EINTR && errno != EAGAIN))) { + nfds--; + FD_CLR (pipe_out[0], &setin); + } + } + } + close (pipe_in[1]); + close (pipe_out[0]); + + int cgistat; + if (waitpid (pid, &cgistat, 0) > 0) { + if (WIFSIGNALED (cgistat)) { + chttpd_log_write (hlog, "[%4llu] 500 Internal Server Error: " + "CGI program is terminated by signal %d", WTERMSIG (cgistat)); + lbs_posix_write_all (connfd, + http_status_hdr[HTTP_STATUS_500_INTERNAL_SERVER_ERROR], 0); + lbs_posix_write_all (connfd, + "Content-Type: text/html" NL NL, 0); + lbs_posix_write_all (connfd, + "\n<html><head><title>500 Internal Server Error</title></head>" NL + "<body><p>CGI program was terminated abnormally." NL + "<a href=\"http://tools.ietf.org/search/rfc2616#section-10.5.1\">" + "[500]</a></p></body></html>" NL, 0); + goto http_exit; + } + } + + FILE* connfp = fdopen (dup (connfd), "wb"); + if (connfp == NULL) { + chttpd_log_write (hlog, "[%4llu] cannot open a stdio stream ... " + "send all CGI program output to client!"); + lbs_posix_write_all (connfd, out_buf->data, out_buf->len); + goto http_exit; + } + + /* Compute Content-Length */ + char* out_content = internal_memstr (out_buf->data, out_buf->len, hdr_delim); + size_t out_content_len; + size_t out_hdr_len; + bool need_content_len = true; + if (out_content == NULL) { + out_content = ""; + out_hdr_len = out_buf->len; + out_content_len = 0; + } else { + *out_content = '\0'; + out_hdr_len = out_content - (char*)(out_buf->data); + out_content += 4; + out_content_len = (char*)(out_buf->data) + out_buf->len - out_content; + } + + /* Process the header returned by CGI program */ + char* out_line = out_buf->data; + char* delim; + bool out_line_first = true; + do { + delim = internal_memstr (out_line, out_hdr_len, line_delim); + if (delim != NULL) { + *delim = '\0'; + delim += 2; + out_hdr_len -= delim - out_line; + } + if (out_line_first) { + if (lbs_str_has_prefix (out_line, "HTTP/1.1 ")) { + chttpd_log_write (hlog, "[%4llu] CGI program says %s", + id, out_line); + fputs (out_line, connfp); + } else { + chttpd_log_write (hlog, "[%4llu] CGI program does not specify " + "HTTP status (assume 200 OK)", id); + fputs ("HTTP/1.1 200 OK", connfp); + } + } else { + if (lbs_str_has_prefix (out_line, "Content-Length:")) { + need_content_len = false; + } + fputs (out_line, connfp); + } + fputs (NL, connfp); + out_line_first = false; + } while (delim != NULL); + + if (need_content_len) { + fprintf (connfp, "Content-Length: %zu" NL, out_content_len); + } + fputs (NL, connfp); + fclose (connfp); + if (out_content_len > 0) { + lbs_posix_write_all (connfd, out_content, out_content_len); + } http_exit: lbs_array_unref (hdr_buf); diff --git a/hw4/l4basic/l4str.c b/hw4/l4basic/l4str.c index 5569f7a..d0a4894 100644 --- a/hw4/l4basic/l4str.c +++ b/hw4/l4basic/l4str.c @@ -9,7 +9,7 @@ bool lbs_str_has_prefix (const char* str, const char* prefix) { int i; - for (i = 0; str != '\0' && prefix[i] != '\0'; i++) { + for (i = 0; str[i] != '\0' && prefix[i] != '\0'; i++) { if (str[i] != prefix[i]) { return false; } |