summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2014-01-15 06:33:03 +0800
committerLAN-TW <lantw44@gmail.com>2014-01-15 06:33:03 +0800
commit01b4949633b43d88f3ee319491db73b93987247a (patch)
tree4bf5fe00218a60dfc163071f56d2143dab579a6e
parent9d8903de3ca42b6daf2b716f2c1683430ca5e2b9 (diff)
downloadsp2013-01b4949633b43d88f3ee319491db73b93987247a.tar.gz
sp2013-01b4949633b43d88f3ee319491db73b93987247a.tar.zst
sp2013-01b4949633b43d88f3ee319491db73b93987247a.zip
HW4: 基本 CGI 功能已經可以使用,但尚未完整測試
-rw-r--r--hw4/chttpd/chttpd-conn.c171
-rw-r--r--hw4/l4basic/l4str.c2
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;
}