Changeset 4a4cc150 in mainline for uspace/app/websrv/websrv.c
- Timestamp:
- 2011-12-10T22:32:55Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 9c3bba0
- Parents:
- b5eae30
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/websrv/websrv.c
rb5eae30 r4a4cc150 1 1 /* 2 * Copyright (c) 201 0Jiri Svoboda2 * Copyright (c) 2011 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 31 31 */ 32 32 /** 33 * @file (Less-than-skeleton)web server.33 * @file Skeletal web server. 34 34 */ 35 35 36 #include <bool.h> 37 #include <errno.h> 36 38 #include <stdio.h> 39 #include <sys/types.h> 40 #include <sys/stat.h> 41 #include <fcntl.h> 37 42 38 43 #include <net/in.h> … … 44 49 #define PORT_NUMBER 8080 45 50 51 #define WEB_ROOT "/data/web" 52 46 53 /** Buffer for receiving the request. */ 47 54 #define BUFFER_SIZE 1024 48 static char buf[BUFFER_SIZE]; 55 static char rbuf[BUFFER_SIZE]; 56 static size_t rbuf_out, rbuf_in; 57 58 static char lbuf[BUFFER_SIZE + 1]; 59 static size_t lbuf_used; 60 61 static char fbuf[BUFFER_SIZE]; 49 62 50 63 /** Response to send to client. */ 51 static const char * response_msg =64 static const char *ok_msg = 52 65 "HTTP/1.0 200 OK\r\n" 53 "\r\n" 54 "<h1>Hello from HelenOS!</h1>\r\n"; 66 "\r\n"; 67 68 /** Receive one character (with buffering) */ 69 static int recv_char(int fd, char *c) 70 { 71 ssize_t rc; 72 73 if (rbuf_out == rbuf_in) { 74 rbuf_out = 0; 75 rbuf_in = 0; 76 77 rc = recv(fd, rbuf, BUFFER_SIZE, 0); 78 if (rc <= 0) { 79 printf("recv() failed (%zd)\n", rc); 80 return rc; 81 } 82 83 rbuf_in = rc; 84 } 85 86 *c = rbuf[rbuf_out++]; 87 return EOK; 88 } 89 90 /** Receive one line with length limit. */ 91 static int recv_line(int fd) 92 { 93 char c, prev; 94 int rc; 95 char *bp; 96 97 bp = lbuf; c = '\0'; 98 while (bp < lbuf + BUFFER_SIZE) { 99 prev = c; 100 rc = recv_char(fd, &c); 101 if (rc != EOK) 102 return rc; 103 104 *bp++ = c; 105 if (prev == '\r' && c == '\n') 106 break; 107 } 108 109 lbuf_used = bp - lbuf; 110 *bp = '\0'; 111 112 if (bp == lbuf + BUFFER_SIZE) 113 return ELIMIT; 114 115 return EOK; 116 } 117 118 static bool uri_is_valid(char *uri) 119 { 120 char *cp; 121 char c; 122 123 if (uri[0] != '/') 124 return false; 125 if (uri[1] == '.') 126 return false; 127 128 cp = uri + 1; 129 while (*cp != '\0') { 130 c = *cp++; 131 if (c == '/') 132 return false; 133 } 134 135 return true; 136 } 137 138 static int send_response(int conn_sd, const char *msg) 139 { 140 size_t response_size; 141 ssize_t rc; 142 143 response_size = str_size(msg); 144 145 /* Send a canned response. */ 146 printf("Send response...\n"); 147 rc = send(conn_sd, (void *) msg, response_size, 0); 148 if (rc < 0) { 149 printf("send() failed.\n"); 150 return rc; 151 } 152 153 return EOK; 154 } 155 156 static int uri_get(const char *uri, int conn_sd) 157 { 158 int rc; 159 char *fname; 160 int fd; 161 ssize_t nr; 162 163 if (str_cmp(uri, "/") == 0) 164 uri = "/index.htm"; 165 166 rc = asprintf(&fname, "%s%s", WEB_ROOT, uri); 167 if (rc < 0) 168 return ENOMEM; 169 170 fd = open(fname, O_RDONLY); 171 if (fd < 0) { 172 printf("File '%s' not found.\n", fname); 173 return ENOENT; 174 } 175 176 rc = send_response(conn_sd, ok_msg); 177 if (rc != EOK) 178 return rc; 179 180 while (true) { 181 nr = read(fd, fbuf, BUFFER_SIZE); 182 if (nr == 0) 183 break; 184 185 if (nr < 0) { 186 close(fd); 187 return EIO; 188 } 189 190 rc = send(conn_sd, fbuf, nr, 0); 191 if (rc < 0) { 192 printf("send() failed\n"); 193 close(fd); 194 return rc; 195 } 196 } 197 198 close(fd); 199 200 return EOK; 201 } 202 203 static int req_process(int conn_sd) 204 { 205 int rc; 206 char *uri, *end_uri; 207 208 rc = recv_line(conn_sd); 209 if (rc != EOK) { 210 printf("recv_line() failed\n"); 211 return rc; 212 } 213 214 printf("%s", lbuf); 215 216 if (str_lcmp(lbuf, "GET ", 4) != 0) { 217 printf("Invalid HTTP method.\n"); 218 return EINVAL; 219 } 220 221 uri = lbuf + 4; 222 end_uri = str_chr(uri, ' '); 223 if (end_uri == NULL) { 224 end_uri = lbuf + lbuf_used - 2; 225 assert(*end_uri == '\r'); 226 } 227 228 *end_uri = '\0'; 229 printf("Requested URI '%s'.\n", uri); 230 231 if (!uri_is_valid(uri)) { 232 printf("Invalid request URI.\n"); 233 return EINVAL; 234 } 235 236 return uri_get(uri, conn_sd); 237 } 55 238 56 239 int main(int argc, char *argv[]) … … 64 247 int rc; 65 248 66 size_t response_size;67 249 68 250 addr.sin_family = AF_INET; … … 94 276 return 1; 95 277 } 96 97 response_size = str_size(response_msg);98 278 99 279 printf("Listening for connections at port number %u.\n", PORT_NUMBER); … … 105 285 if (conn_sd < 0) { 106 286 printf("accept() failed.\n"); 107 return 1;287 continue; 108 288 } 109 289 … … 111 291 112 292 printf("Wait for client request\n"); 113 114 /* Really we should wait for a blank line. */ 115 rc = recv(conn_sd, buf, BUFFER_SIZE, 0); 116 if (rc < 0) { 117 printf("recv() failed\n"); 118 return 1; 119 } 120 121 /* Send a canned response. */ 122 printf("Send response...\n"); 123 rc = send(conn_sd, (void *) response_msg, response_size, 0); 124 if (rc < 0) { 125 printf("send() failed.\n"); 126 return 1; 127 } 293 rbuf_out = rbuf_in = 0; 294 295 rc = req_process(conn_sd); 296 if (rc != EOK) 297 printf("Error processing request.\n"); 128 298 129 299 rc = closesocket(conn_sd);
Note:
See TracChangeset
for help on using the changeset viewer.