Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 1 | |
| 2 | #include <ngx_config.h> |
| 3 | #include <ngx_log.h> |
| 4 | #include <ngx_alloc.h> |
| 5 | #include <ngx_hunk.h> |
| 6 | #include <ngx_connection.h> |
| 7 | |
| 8 | #include <ngx_http.h> |
| 9 | |
| 10 | /* |
| 11 | ngx_read should check errors (if we ask) and return |
| 12 | -2 EAGAIN |
| 13 | -1 error |
| 14 | 0 EOF |
| 15 | >0 number of bytes |
| 16 | */ |
| 17 | |
| 18 | int ngx_http_init_connection(ngx_connection_t *c); |
| 19 | static int ngx_http_init_request(ngx_event_t *ev); |
| 20 | static int ngx_http_process_request(ngx_event_t *ev); |
| 21 | |
| 22 | static int ngx_process_http_request_line(ngx_http_request_t *r); |
| 23 | static int ngx_process_http_request_header(ngx_http_request_t *r); |
| 24 | |
| 25 | static int ngx_process_http_request(ngx_http_request_t *r); |
| 26 | |
| 27 | static int ngx_http_close_request(ngx_event_t *ev); |
| 28 | |
| 29 | /* |
| 30 | returns |
| 31 | -1 if error |
| 32 | 0 need more data or EOF (filter is deleted) |
| 33 | 1 there is unread data |
| 34 | */ |
| 35 | |
| 36 | int ngx_http_init_connection(ngx_connection_t *c) |
| 37 | { |
| 38 | ngx_event_t *ev; |
| 39 | |
| 40 | ev = c->read; |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 41 | ev->event_handler = ngx_http_init_request; |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 42 | ev->log->action = "reading client request line"; |
| 43 | |
| 44 | ngx_log_debug(ev->log, "ngx_http_init_connection: entered"); |
| 45 | |
| 46 | /* XXX: ev->timer ? */ |
| 47 | if (ngx_add_event(ev, NGX_TIMER_EVENT, ev->timer) == -1) |
| 48 | return -1; |
| 49 | |
| 50 | #if (HAVE_DEFERRED_ACCEPT) |
| 51 | if (ev->ready) |
| 52 | return ngx_http_init_request(ev); |
| 53 | else |
| 54 | #endif |
| 55 | #if (NGX_CLEAR_EVENT) |
| 56 | return ngx_add_event(ev, NGX_READ_EVENT, NGX_CLEAR_EVENT); |
| 57 | #else |
| 58 | return ngx_add_event(ev, NGX_READ_EVENT, NGX_ONESHOT_EVENT); |
| 59 | #endif |
| 60 | } |
| 61 | |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 62 | int ngx_http_init_request(ngx_event_t *ev) |
| 63 | { |
| 64 | ngx_connection_t *c = (ngx_connection_t *) ev->data; |
| 65 | ngx_http_request_t *r; |
| 66 | |
| 67 | ngx_log_debug(ev->log, "ngx_http_init_request: entered"); |
| 68 | |
Igor Sysoev | 0c331d9 | 2002-08-15 17:20:26 +0000 | [diff] [blame] | 69 | ngx_test_null(c->pool, ngx_create_pool(16384, ev->log), -1); |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 70 | ngx_test_null(r, ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)), -1); |
| 71 | |
| 72 | c->data = r; |
| 73 | r->connection = c; |
| 74 | |
Igor Sysoev | 0c331d9 | 2002-08-15 17:20:26 +0000 | [diff] [blame] | 75 | ngx_test_null(r->pool, ngx_create_pool(16384, ev->log), -1); |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 76 | ngx_test_null(r->buff, ngx_palloc(r->pool, sizeof(ngx_buff_t)), -1); |
| 77 | ngx_test_null(r->buff->buff, |
| 78 | ngx_pcalloc(r->pool, sizeof(c->server->buff_size)), -1); |
| 79 | |
| 80 | r->buff->pos = r->buff->last = r->buff->buff; |
| 81 | r->buff->end = r->buff->buff + c->server->buff_size; |
| 82 | |
| 83 | r->state_handler = ngx_process_http_request_line; |
| 84 | |
| 85 | ev->event_handler = ngx_http_process_request; |
| 86 | ev->close_handler = ngx_http_close_request; |
| 87 | c->write->close_handler = ngx_http_close_request; |
| 88 | return ngx_http_process_request(ev); |
| 89 | } |
| 90 | |
| 91 | int ngx_http_process_request(ngx_event_t *ev) |
| 92 | { |
| 93 | int n; |
| 94 | ngx_connection_t *c = (ngx_connection_t *) ev->data; |
| 95 | ngx_http_request_t *r = (ngx_http_request_t *) c->data; |
| 96 | |
| 97 | ngx_log_debug(ev->log, "http process request"); |
| 98 | |
Igor Sysoev | 0c331d9 | 2002-08-15 17:20:26 +0000 | [diff] [blame] | 99 | n = ngx_event_recv(ev, r->buff->last, r->buff->end - r->buff->last); |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 100 | |
Igor Sysoev | 0c331d9 | 2002-08-15 17:20:26 +0000 | [diff] [blame] | 101 | if (n == -2) |
| 102 | return 0; |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 103 | |
Igor Sysoev | 0c331d9 | 2002-08-15 17:20:26 +0000 | [diff] [blame] | 104 | if (n == -1) |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 105 | return -1; |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 106 | |
Igor Sysoev | 0c331d9 | 2002-08-15 17:20:26 +0000 | [diff] [blame] | 107 | ngx_log_debug(ev->log, "http read %d" _ n); |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 108 | |
| 109 | if (n == 0) { |
| 110 | if (ev->unexpected_eof) { |
| 111 | ngx_log_error(NGX_LOG_INFO, ev->log, 0, |
| 112 | "ngx_http_process_request: " |
| 113 | "connection is closed while %s", ev->action); |
| 114 | return -1; |
| 115 | } |
| 116 | |
| 117 | return ngx_http_close_request(ev); |
| 118 | } |
| 119 | |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 120 | if (!ev->read_discarded) { |
| 121 | r->buff->last += n; |
| 122 | |
| 123 | /* state_handlers are called in following order: |
| 124 | ngx_process_http_request_line() |
| 125 | ngx_process_http_request_header() */ |
| 126 | |
| 127 | do { |
| 128 | if ((r->state_handler)(r) < 0) |
| 129 | return -1; |
| 130 | } while (r->buff->pos < r->buff->last); |
| 131 | } |
| 132 | |
| 133 | if (ngx_del_event(ev, NGX_TIMER_EVENT) == -1) |
| 134 | return -1; |
| 135 | |
| 136 | if (ngx_add_event(ev, NGX_TIMER_EVENT, ev->timer) == -1) |
| 137 | return -1; |
| 138 | |
| 139 | return 0; |
| 140 | } |
| 141 | |
| 142 | static int ngx_process_http_request_line(ngx_http_request_t *r) |
| 143 | { |
| 144 | int n; |
| 145 | |
| 146 | if ((n = ngx_read_http_request_line(r)) == 1) { |
| 147 | *r->uri_end = '\0'; |
Igor Sysoev | 0c331d9 | 2002-08-15 17:20:26 +0000 | [diff] [blame] | 148 | ngx_log_debug(r->connection->log, "HTTP: %d, %d, %s" _ |
| 149 | r->method _ r->http_version _ r->uri_start); |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 150 | r->state_handler = ngx_process_http_request_header; |
| 151 | r->connection->read->action = "reading client request headers"; |
| 152 | } |
| 153 | |
| 154 | return n; |
| 155 | } |
| 156 | |
| 157 | static int ngx_process_http_request_header(ngx_http_request_t *r) |
| 158 | { |
| 159 | int n; |
| 160 | |
| 161 | while ((n = ngx_read_http_header_line(r)) == 1) { |
| 162 | *r->header_name_end = '\0'; |
| 163 | *r->header_end = '\0'; |
Igor Sysoev | 0c331d9 | 2002-08-15 17:20:26 +0000 | [diff] [blame] | 164 | ngx_log_debug(r->connection->log, "HTTP header: '%s: %s'" _ |
| 165 | r->header_name_start _ r->header_start); |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | if (n != 2) |
| 169 | return n; |
| 170 | |
| 171 | r->state_handler = NULL; |
| 172 | r->connection->read->action = "reading client request body"; |
| 173 | |
| 174 | r->connection->read->read_discarded = 1; |
| 175 | r->connection->read->unexpected_eof = 0; |
| 176 | ngx_log_debug(r->connection->log, "HTTP header done"); |
| 177 | |
| 178 | return ngx_process_http_request(r); |
| 179 | } |
| 180 | |
| 181 | static int ngx_process_http_request(ngx_http_request_t *r) |
| 182 | { |
Igor Sysoev | e0af1b8 | 2002-08-16 15:27:03 +0000 | [diff] [blame^] | 183 | int err; |
| 184 | char *name, *loc, *file; |
| 185 | |
| 186 | ngx_log_debug(r->connection->log, "HTTP request"); |
| 187 | |
| 188 | if (*(r->uri_end - 1) == '/') { |
| 189 | r->handler = NGX_HTTP_DIRECTORY_HANDLER; |
| 190 | return NGX_OK; |
| 191 | } |
| 192 | |
| 193 | /* 20 bytes is spare space for some index name, i.e. index.html */ |
| 194 | r->filename_len = r->uri_end - r->uri_start + r->server->doc_root_len + 20; |
| 195 | |
| 196 | ngx_test_null(r->filename, |
| 197 | ngx_palloc(r->pool, r->filename_len), |
| 198 | ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR)); |
| 199 | |
| 200 | r->location = ngx_cpystrn(r->filename, r->server->doc_root, |
| 201 | r->server->doc_root_len); |
| 202 | file = ngx_cpystrn(r->location, r->uri_start, |
| 203 | r->uri_end - r->uri_start + 1); |
| 204 | |
| 205 | ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ r->filename); |
| 206 | |
| 207 | } |
| 208 | #if 0 |
| 209 | |
| 210 | if (ngx_stat(r->filename, &r->stat) == -1) { |
| 211 | err = ngx_errno; |
| 212 | ngx_log_error(GX_LOG_ERR, r->connection->log, err, |
| 213 | "ngx_process_http_request: " |
| 214 | ngx_stat_n " %s failed", r->filename); |
| 215 | |
| 216 | if (err == NGX_ENOENT) |
| 217 | return ngx_http_error(r, NGX_HTTP_NOT_FOUND); |
| 218 | else |
| 219 | return ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 220 | } |
| 221 | |
| 222 | if (ngx_is_dir(r->stat)) { |
| 223 | *file++ = '/'; |
| 224 | *file = '\0'; |
| 225 | r->headers_out->location = r->location; |
| 226 | return ngx_http_redirect(r, NGX_HTTP_MOVED_PERMANENTLY); |
| 227 | } |
| 228 | |
| 229 | r->stat_valid = 1; |
| 230 | r->handler = NGX_HTTP_STATIC_HANDLER; |
| 231 | return NGX_OK; |
| 232 | } |
| 233 | |
| 234 | static int ngx_http_handler(ngx_http_request_t *r, int handler) |
| 235 | { |
| 236 | if (handler == NGX_HTTP_STATIC_HANDLER) |
| 237 | return ngx_http_static_handler(r); |
| 238 | |
| 239 | elsif (handler == NGX_HTTP_DIRECTORY_HANDLER) |
| 240 | return ngx_http_index_handler(r); |
| 241 | |
| 242 | return ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
| 243 | } |
| 244 | #endif |
| 245 | |
| 246 | static int ngx_http_redirect(ngx_http_request_t *r, int redirect) |
| 247 | { |
| 248 | /* STUB */ |
| 249 | return -1; |
| 250 | } |
| 251 | |
| 252 | static int ngx_http_error(ngx_http_request_t *r, int error) |
| 253 | { |
| 254 | /* STUB */ |
Igor Sysoev | 0c331d9 | 2002-08-15 17:20:26 +0000 | [diff] [blame] | 255 | return -1; |
| 256 | } |
| 257 | |
| 258 | #if 0 |
| 259 | |
| 260 | static int ngx_process_http_request(ngx_http_request_t *r) |
| 261 | { |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 262 | int fd; |
| 263 | struct stat sb; |
| 264 | ngx_http_header_out_t *header_out; |
| 265 | ngx_chunk_t *header, *ch; |
| 266 | |
| 267 | int index = (*(r->uri_end - 1) == '/') ? sizeof(NGX_INDEX) : 1; |
| 268 | char *name = ngx_palloc(r->pool, |
| 269 | r->uri_end - r->uri_start + strlen(ngx_root) + index); |
| 270 | strcpy(name, ngx_root); |
| 271 | strcat(name, r->uri_start); |
| 272 | if (*(r->uri_end - 1) == '/') |
| 273 | strcat(name, NGX_INDEX); |
| 274 | |
| 275 | ngx_log_debug(r->connection->log, "HTTP URI: '%s'", name); |
| 276 | |
| 277 | if ((fd = open(name, O_RDONLY)) == -1) { |
| 278 | ngx_log_error(NGX_LOG_ERR, r->connection->log, errno, |
| 279 | "open %s failed", name); |
| 280 | return -1; |
| 281 | } |
| 282 | |
| 283 | if (fstat(fd, &sb) == -1) { |
| 284 | ngx_log_error(NGX_LOG_ERR, r->connection->log, errno, |
| 285 | "fstat %s failed", name); |
| 286 | return -1; |
| 287 | } |
| 288 | |
| 289 | header_out = ngx_palloc(r->pool, sizeof(ngx_http_header_out_t)); |
| 290 | |
| 291 | header_out->status = NGX_HTTP_OK; |
| 292 | header_out->content_length = sb.st_size; |
| 293 | header_out->last_modified = sb.st_mtime; |
| 294 | header_out->content_type = "text/html"; |
| 295 | header_out->charset = "koi8-r"; |
| 296 | header_out->date = time(NULL); |
| 297 | header_out->connection = NGX_HTTP_CONN_CLOSE; |
| 298 | |
| 299 | /* |
| 300 | header_out->connection = NGX_HTTP_CONN_KEEP_ALIVE; |
| 301 | r->connection->read->event_handler = ngx_http_init_request; |
| 302 | */ |
| 303 | |
| 304 | header = ngx_http_header(r, header_out); |
| 305 | ch = ngx_palloc(r->pool, sizeof(ngx_chunk_t)); |
| 306 | ch->ident = fd; |
| 307 | ch->offset = 0; |
| 308 | ch->size = sb.st_size; |
| 309 | ch->next = NULL; |
| 310 | header->next = ch; |
| 311 | |
| 312 | ngx_event_write(r->connection, header); |
| 313 | |
| 314 | return 0; |
| 315 | } |
| 316 | |
Igor Sysoev | 0c331d9 | 2002-08-15 17:20:26 +0000 | [diff] [blame] | 317 | #endif |
| 318 | |
Igor Sysoev | 6de5c2c | 2002-08-06 16:39:45 +0000 | [diff] [blame] | 319 | static int ngx_http_close_request(ngx_event_t *ev) |
| 320 | { |
| 321 | ngx_connection_t *c = (ngx_connection_t *) ev->data; |
| 322 | |
| 323 | ngx_log_debug(ev->log, "http close"); |
| 324 | |
| 325 | ngx_del_event(c->read, NGX_TIMER_EVENT); |
| 326 | ngx_del_event(c->write, NGX_TIMER_EVENT); |
| 327 | |
| 328 | return ngx_event_close(ev); |
| 329 | } |