00001 /* 00002 More-complete Web Server 00003 AUP2, Sec. 8.04.4 (not in book) 00004 00005 Copyright 2003 by Marc J. Rochkind. All rights reserved. 00006 May be copied only for purposes and under conditions described 00007 on the Web page www.basepath.com/aup/copyright.htm. 00008 00009 The Example Files are provided "as is," without any warranty; 00010 without even the implied warranty of merchantability or fitness 00011 for a particular purpose. The author and his publisher are not 00012 responsible for any damages, direct or incidental, resulting 00013 from the use or non-use of these Example Files. 00014 00015 The Example Files may contain defects, and some contain deliberate 00016 coding mistakes that were included for educational reasons. 00017 You are responsible for determining if and how the Example Files 00018 are to be used. 00019 00020 */ 00021 #include "defs.h" 00022 #include "ssi.h" 00023 00024 /* rfc2616 */ 00025 00026 /* use basename? *********************************************************/ 00027 00028 #define WEB_ROOT "/aup/webroot/" 00029 #define NOTFOUND_PAGE "/aup/notfound.htm" 00030 00031 #define HEADER_OK\ 00032 "HTTP/1.1 200 OK\r\n"\ 00033 "Server: AUP-ws\r\n"\ 00034 "Content-Length: %ld\r\n" 00035 00036 #define CONTENT_TEXT\ 00037 "Content-Type: text/html\r\n\r\n" 00038 00039 #define CONTENT_JPEG\ 00040 "Content-Type: image/jpeg\r\n\r\n" 00041 00042 #define HEADER_NOTFOUND\ 00043 "HTTP/1.1 404 Not Found\r\n"\ 00044 "Server: AUP-ws\r\n"\ 00045 "Transfer-Encoding: chunked\r\n"\ 00046 "Content-Type: text/html\r\n\r\n" 00047 00048 #define HTML_NOTFOUND\ 00049 "<!DOCTYPE html PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"\ 00050 "<html><head><title>Error 404</title>\n"\ 00051 "</head><body>\n"\ 00052 "<h2>AUP-ws server can't find page %s</h2>"\ 00053 "</body></html>\r\n" 00054 00055 00056 static void send_header_OK(SSI *ssip, off_t len, const char *path, int fd) 00057 { 00058 char buf[1000], *dot; 00059 00060 snprintf(buf, sizeof(buf), HEADER_OK, (long)len); 00061 ec_neg1( writeall(fd, buf, strlen(buf)) ) 00062 /* Following is extremely oversimplified */ 00063 dot = strrchr(path, '.'); 00064 if (dot != NULL && (strcasecmp(dot, ".jpg") == 0 || 00065 strcasecmp(dot, ".jpeg") == 0)) 00066 ec_neg1( writeall(fd, CONTENT_JPEG, strlen(CONTENT_JPEG)) ) 00067 else { 00068 time_t tm; 00069 char buf[100]; 00070 00071 ec_neg1( writeall(fd, CONTENT_TEXT, strlen(CONTENT_TEXT)) ) 00072 (void)time(&tm); 00073 strcpy(buf, ctime(&tm)); 00074 ec_neg1( writeall(fd, buf, strlen(buf)) ) 00075 } 00076 return; 00077 00078 EC_CLEANUP_BGN 00079 EC_FLUSH("Error sending response (nonfatal)") 00080 EC_CLEANUP_END 00081 } 00082 00083 static void send_header_notfound(SSI *ssip, const char *path, int fd) 00084 { 00085 char buf[2000], buf_html[1000]; 00086 00087 /* Bug: Should remove meta-characters from path. */ 00088 snprintf(buf_html, sizeof(buf_html), HTML_NOTFOUND, path); 00089 snprintf(buf, sizeof(buf), "%s%x\r\n%s\r\n0\r\n\r\n", 00090 HEADER_NOTFOUND, strlen(buf_html), buf_html); 00091 ec_neg1( writeall(fd, buf, strlen(buf)) ) 00092 return; 00093 00094 EC_CLEANUP_BGN 00095 EC_FLUSH("Error sending response (nonfatal)") 00096 EC_CLEANUP_END 00097 } 00098 00099 static bool handle_request(SSI *ssip, const char *s, int fd) 00100 { 00101 char *p, buf[1000], path[FILENAME_MAX];// wrong macro 00102 FILE *in; 00103 struct stat statbuf; 00104 ssize_t nread, nsent, nsenttotal = 0; 00105 00106 if (strncasecmp(s, "GET ", 4) == 0) { 00107 s += 4; 00108 p = strchr(s, ' '); 00109 if (p != NULL) 00110 *p = '\0'; 00111 strcpy(path, WEB_ROOT); 00112 strncat(path, s, sizeof(path)); 00113 if (stat(path, &statbuf) == 0 && 00114 (statbuf.st_mode & S_IFDIR) == S_IFDIR) { 00115 if (path[strlen(path) - 1] != '/') 00116 strncat(path, "/", sizeof(path)); 00117 strncat(path, "index.html", sizeof(path)); 00118 } 00119 if (stat(path, &statbuf) == -1 || 00120 (in = fopen(path, "rb")) == NULL) { 00121 send_header_notfound(ssip, s, fd); 00122 return false; 00123 } 00124 send_header_OK(ssip, statbuf.st_size, path, fd); 00125 // use sendfile or whatever the fast thingy is 00126 while ((nread = fread(buf, 1, sizeof(buf), in)) > 0) { 00127 ec_neg1( nsent = writeall(fd, buf, nread) ) 00128 nsenttotal += nsent; 00129 } 00130 if (statbuf.st_size != nsenttotal) 00131 printf("Sizes different stat = %ld; sent = %d\n", 00132 (long)statbuf.st_size, nsenttotal); 00133 (void)fclose(in); 00134 } 00135 else 00136 printf("Unknown request: %.25s\n", s); 00137 return true; 00138 00139 EC_CLEANUP_BGN 00140 EC_FLUSH("Error sending response (nonfatal)") 00141 return false; 00142 EC_CLEANUP_END 00143 } 00144 00145 int main(int argc, char *argv[]) 00146 { 00147 SSI *ssip = NULL; 00148 char msg[1600]; 00149 ssize_t nrcv; 00150 int i, fd, c; 00151 char hostbuf[100] = "//", *host = NULL; 00152 00153 while ((c = getopt(argc, argv, ":h:")) != -1) 00154 switch(c) { 00155 case 'h': 00156 host = optarg; 00157 break; 00158 case ':': 00159 fprintf(stderr, "Option -%c requires an operand\n", optopt); 00160 /* fall through */ 00161 default: 00162 fprintf(stderr, "Usage: ws [-h host]\n"); 00163 exit(EXIT_FAILURE); 00164 } 00165 if (host == NULL) { 00166 ec_neg1( gethostname(&hostbuf[2], sizeof(hostbuf) - 2) ) /* leave // there */ 00167 host = hostbuf; 00168 } 00169 if (strchr(host, ':') == NULL) 00170 strcat(host, ":8000"); 00171 printf("Connecting to host \"%s\"\n", host); 00172 ec_null( ssip = ssi_open(host, true) ) 00173 printf("\t...connected\n"); 00174 while (true) { 00175 ec_neg1( fd = ssi_wait_server(ssip) ) 00176 nrcv = read(fd, msg, sizeof(msg)); 00177 switch (nrcv) { 00178 case 0: 00179 continue; 00180 case -1: 00181 if (errno == ECONNRESET) 00182 fprintf(stderr, "ECONNRESET\n"); 00183 syserr_print("smi_receive_skt_string got error (nonfatal)\n"); 00184 continue; 00185 default: 00186 msg[nrcv] = '\0'; 00187 printf("Got %d bytes:\n", nrcv); 00188 for (i = 0; i < nrcv; i++) { 00189 if (isgraph((int)msg[i]) || isspace((int)msg[i])) 00190 printf("%c", msg[i]); 00191 else 00192 printf("'\\%o'", msg[i]); 00193 } 00194 (void)handle_request(ssip, msg, fd); 00195 } 00196 } 00197 ec_false( ssi_close(ssip) ) 00198 printf("Done.\n"); 00199 exit(EXIT_SUCCESS); 00200 00201 EC_CLEANUP_BGN 00202 return EXIT_FAILURE; 00203 EC_CLEANUP_END 00204 }