| Date: | 2010-08-12 01:44:30 (2 years 9 months ago) |
|---|---|
| Author: | jow |
| Commit: | 01658f6e25197d603a1fcd0c14eda097316bf5a2 |
| Message: | [package] uhttpd: - abort file serving if client connection is lost (#7742) - don't send bad request headers twice git-svn-id: svn://svn.openwrt.org/openwrt/trunk@22602 3c298f89-4303-0410-b956-a3cf2f4a3e73 |
| Files: |
package/uhttpd/Makefile (1 diff) package/uhttpd/src/uhttpd-file.c (8 diffs) package/uhttpd/src/uhttpd.c (1 diff) |
Change Details
| package/uhttpd/Makefile | ||
|---|---|---|
| 8 | 8 | include $(TOPDIR)/rules.mk |
| 9 | 9 | |
| 10 | 10 | PKG_NAME:=uhttpd |
| 11 | PKG_RELEASE:=13 | |
| 11 | PKG_RELEASE:=14 | |
| 12 | 12 | |
| 13 | 13 | PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) |
| 14 | 14 | PKG_BUILD_DEPENDS := libcyassl liblua |
| package/uhttpd/src/uhttpd-file.c | ||
|---|---|---|
| 97 | 97 | return NULL; |
| 98 | 98 | } |
| 99 | 99 | |
| 100 | #define ensure_ret(x) \ | |
| 101 | do { if( x < 0 ) return; } while(0) | |
| 102 | ||
| 100 | 103 | static void uh_file_response_ok_hdrs(struct client *cl, struct http_request *req, struct stat *s) |
| 101 | 104 | { |
| 102 | uh_http_sendf(cl, NULL, "Connection: close\r\n"); | |
| 105 | ensure_ret(uh_http_sendf(cl, NULL, "Connection: close\r\n")); | |
| 103 | 106 | |
| 104 | 107 | if( s ) |
| 105 | 108 | { |
| 106 | uh_http_sendf(cl, NULL, "ETag: %s\r\n", uh_file_mktag(s)); | |
| 107 | uh_http_sendf(cl, NULL, "Last-Modified: %s\r\n", uh_file_unix2date(s->st_mtime)); | |
| 109 | ensure_ret(uh_http_sendf(cl, NULL, "ETag: %s\r\n", uh_file_mktag(s))); | |
| 110 | ensure_ret(uh_http_sendf(cl, NULL, "Last-Modified: %s\r\n", uh_file_unix2date(s->st_mtime))); | |
| 108 | 111 | } |
| 109 | 112 | |
| 110 | uh_http_sendf(cl, NULL, "Date: %s\r\n", uh_file_unix2date(time(NULL))); | |
| 113 | ensure_ret(uh_http_sendf(cl, NULL, "Date: %s\r\n", uh_file_unix2date(time(NULL)))); | |
| 111 | 114 | } |
| 112 | 115 | |
| 113 | 116 | static void uh_file_response_200(struct client *cl, struct http_request *req, struct stat *s) |
| 114 | 117 | { |
| 115 | uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", req->version); | |
| 118 | ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", req->version)); | |
| 116 | 119 | uh_file_response_ok_hdrs(cl, req, s); |
| 117 | 120 | } |
| 118 | 121 | |
| 119 | 122 | static void uh_file_response_304(struct client *cl, struct http_request *req, struct stat *s) |
| 120 | 123 | { |
| 121 | uh_http_sendf(cl, NULL, "HTTP/%.1f 304 Not Modified\r\n", req->version); | |
| 124 | ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 304 Not Modified\r\n", req->version)); | |
| 122 | 125 | uh_file_response_ok_hdrs(cl, req, s); |
| 123 | 126 | } |
| 124 | 127 | |
| 125 | 128 | static void uh_file_response_412(struct client *cl, struct http_request *req) |
| 126 | 129 | { |
| 127 | uh_http_sendf(cl, NULL, | |
| 130 | ensure_ret(uh_http_sendf(cl, NULL, | |
| 128 | 131 | "HTTP/%.1f 412 Precondition Failed\r\n" |
| 129 | "Connection: close\r\n", req->version); | |
| 132 | "Connection: close\r\n", req->version)); | |
| 130 | 133 | } |
| 131 | 134 | |
| 132 | 135 | static int uh_file_if_match(struct client *cl, struct http_request *req, struct stat *s) |
| ... | ... | |
| 244 | 247 | } |
| 245 | 248 | |
| 246 | 249 | |
| 250 | #define ensure_out(x) \ | |
| 251 | do { if( x < 0 ) goto out; } while(0) | |
| 252 | ||
| 247 | 253 | static int uh_file_scandir_filter_dir(const struct dirent *e) |
| 248 | 254 | { |
| 249 | 255 | return strcmp(e->d_name, ".") ? 1 : 0; |
| ... | ... | |
| 251 | 257 | |
| 252 | 258 | static void uh_file_dirlist(struct client *cl, struct http_request *req, struct path_info *pi) |
| 253 | 259 | { |
| 254 | int i, count; | |
| 260 | int i; | |
| 261 | int count = 0; | |
| 255 | 262 | char filename[PATH_MAX]; |
| 256 | 263 | char *pathptr; |
| 257 | 264 | struct dirent **files = NULL; |
| 258 | 265 | struct stat s; |
| 259 | 266 | |
| 260 | uh_http_sendf(cl, req, | |
| 267 | ensure_out(uh_http_sendf(cl, req, | |
| 261 | 268 | "<html><head><title>Index of %s</title></head>" |
| 262 | 269 | "<body><h1>Index of %s</h1><hr /><ol>", |
| 263 | 270 | pi->name, pi->name |
| 264 | ); | |
| 271 | )); | |
| 265 | 272 | |
| 266 | 273 | if( (count = scandir(pi->phys, &files, uh_file_scandir_filter_dir, alphasort)) > 0 ) |
| 267 | 274 | { |
| ... | ... | |
| 278 | 285 | if( !stat(filename, &s) && |
| 279 | 286 | (s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH) |
| 280 | 287 | ) |
| 281 | uh_http_sendf(cl, req, | |
| 288 | ensure_out(uh_http_sendf(cl, req, | |
| 282 | 289 | "<li><strong><a href='%s%s'>%s</a>/</strong><br />" |
| 283 | 290 | "<small>modified: %s<br />directory - %.02f kbyte" |
| 284 | 291 | "<br /><br /></small></li>", |
| 285 | 292 | pi->name, files[i]->d_name, files[i]->d_name, |
| 286 | 293 | uh_file_unix2date(s.st_mtime), s.st_size / 1024.0 |
| 287 | ); | |
| 294 | )); | |
| 288 | 295 | |
| 289 | 296 | *pathptr = 0; |
| 290 | 297 | } |
| ... | ... | |
| 298 | 305 | if( !stat(filename, &s) && |
| 299 | 306 | !(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH) |
| 300 | 307 | ) |
| 301 | uh_http_sendf(cl, req, | |
| 308 | ensure_out(uh_http_sendf(cl, req, | |
| 302 | 309 | "<li><strong><a href='%s%s'>%s</a></strong><br />" |
| 303 | 310 | "<small>modified: %s<br />%s - %.02f kbyte<br />" |
| 304 | 311 | "<br /></small></li>", |
| 305 | 312 | pi->name, files[i]->d_name, files[i]->d_name, |
| 306 | 313 | uh_file_unix2date(s.st_mtime), |
| 307 | 314 | uh_file_mime_lookup(filename), s.st_size / 1024.0 |
| 308 | ); | |
| 315 | )); | |
| 309 | 316 | |
| 310 | 317 | *pathptr = 0; |
| 311 | free(files[i]); | |
| 312 | 318 | } |
| 313 | 319 | } |
| 314 | 320 | |
| 315 | free(files); | |
| 321 | ensure_out(uh_http_sendf(cl, req, "</ol><hr /></body></html>")); | |
| 322 | ensure_out(uh_http_sendf(cl, req, "")); | |
| 323 | ||
| 324 | out: | |
| 325 | if( files ) | |
| 326 | { | |
| 327 | for( i = 0; i < count; i++ ) | |
| 328 | free(files[i]); | |
| 316 | 329 | |
| 317 | uh_http_sendf(cl, req, "</ol><hr /></body></html>"); | |
| 318 | uh_http_sendf(cl, req, ""); | |
| 330 | free(files); | |
| 331 | } | |
| 319 | 332 | } |
| 320 | 333 | |
| 321 | 334 | |
| 322 | 335 | void uh_file_request(struct client *cl, struct http_request *req, struct path_info *pi) |
| 323 | 336 | { |
| 324 | int fd, rlen; | |
| 337 | int rlen; | |
| 338 | int fd = -1; | |
| 325 | 339 | char buf[UH_LIMIT_MSGHEAD]; |
| 326 | 340 | |
| 327 | 341 | /* we have a file */ |
| ... | ... | |
| 338 | 352 | /* write status */ |
| 339 | 353 | uh_file_response_200(cl, req, &pi->stat); |
| 340 | 354 | |
| 341 | uh_http_sendf(cl, NULL, "Content-Type: %s\r\n", uh_file_mime_lookup(pi->name)); | |
| 342 | uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size); | |
| 355 | ensure_out(uh_http_sendf(cl, NULL, "Content-Type: %s\r\n", uh_file_mime_lookup(pi->name))); | |
| 356 | ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size)); | |
| 343 | 357 | |
| 344 | 358 | /* if request was HTTP 1.1 we'll respond chunked */ |
| 345 | 359 | if( (req->version > 1.0) && (req->method != UH_HTTP_MSG_HEAD) ) |
| 346 | uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1); | |
| 360 | ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1)); | |
| 347 | 361 | |
| 348 | 362 | /* close header */ |
| 349 | uh_http_send(cl, NULL, "\r\n", -1); | |
| 363 | ensure_out(uh_http_send(cl, NULL, "\r\n", -1)); | |
| 350 | 364 | |
| 351 | 365 | /* send body */ |
| 352 | 366 | if( req->method != UH_HTTP_MSG_HEAD ) |
| 353 | 367 | { |
| 354 | 368 | /* pump file data */ |
| 355 | 369 | while( (rlen = read(fd, buf, sizeof(buf))) > 0 ) |
| 356 | { | |
| 357 | if( uh_http_send(cl, req, buf, rlen) < 0 ) | |
| 358 | break; | |
| 359 | } | |
| 370 | ensure_out(uh_http_send(cl, req, buf, rlen)); | |
| 360 | 371 | |
| 361 | 372 | /* send trailer in chunked mode */ |
| 362 | uh_http_send(cl, req, "", 0); | |
| 373 | ensure_out(uh_http_send(cl, req, "", 0)); | |
| 363 | 374 | } |
| 364 | 375 | } |
| 365 | 376 | |
| 366 | 377 | /* one of the preconditions failed, terminate opened header and exit */ |
| 367 | 378 | else |
| 368 | 379 | { |
| 369 | uh_http_send(cl, NULL, "\r\n", -1); | |
| 380 | ensure_out(uh_http_send(cl, NULL, "\r\n", -1)); | |
| 370 | 381 | } |
| 371 | ||
| 372 | close(fd); | |
| 373 | 382 | } |
| 374 | 383 | |
| 375 | 384 | /* directory */ |
| ... | ... | |
| 379 | 388 | uh_file_response_200(cl, req, NULL); |
| 380 | 389 | |
| 381 | 390 | if( req->version > 1.0 ) |
| 382 | uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1); | |
| 391 | ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1)); | |
| 383 | 392 | |
| 384 | uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1); | |
| 393 | ensure_out(uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1)); | |
| 385 | 394 | |
| 386 | 395 | /* content */ |
| 387 | 396 | uh_file_dirlist(cl, req, pi); |
| ... | ... | |
| 390 | 399 | /* 403 */ |
| 391 | 400 | else |
| 392 | 401 | { |
| 393 | uh_http_sendhf(cl, 403, "Forbidden", | |
| 394 | "Access to this resource is forbidden"); | |
| 402 | ensure_out(uh_http_sendhf(cl, 403, "Forbidden", | |
| 403 | "Access to this resource is forbidden")); | |
| 395 | 404 | } |
| 405 | ||
| 406 | out: | |
| 407 | if( fd > -1 ) | |
| 408 | close(fd); | |
| 396 | 409 | } |
| 397 | 410 | |
| package/uhttpd/src/uhttpd.c | ||
|---|---|---|
| 1001 | 1001 | } |
| 1002 | 1002 | } |
| 1003 | 1003 | |
| 1004 | /* 400 */ | |
| 1005 | else | |
| 1006 | { | |
| 1007 | uh_http_sendhf(cl, 400, "Bad Request", | |
| 1008 | "Malformed request received"); | |
| 1009 | } | |
| 1010 | ||
| 1011 | 1004 | #ifdef HAVE_TLS |
| 1012 | 1005 | /* free client tls context */ |
| 1013 | 1006 | if( conf.tls ) |
