📄 libhttpd.c
字号:
return -1; } realloc_str( &hc->expnfilename, &hc->maxexpnfilename, strlen( cp ) ); (void) strcpy( hc->expnfilename, cp ); realloc_str( &hc->pathinfo, &hc->maxpathinfo, strlen( pi ) ); (void) strcpy( hc->pathinfo, pi ); /* Remove pathinfo stuff from the original filename too. */ if ( hc->pathinfo[0] != '\0' ) { int i; i = strlen( hc->origfilename ) - strlen( hc->pathinfo ); if ( i > 0 && strcmp( &hc->origfilename[i], hc->pathinfo ) == 0 ) hc->origfilename[i - 1] = '\0'; } /* If the expanded filename is an absolute path, check that it's still ** within the current directory or the alternate directory. */ if ( hc->expnfilename[0] == '/' ) { if ( strncmp( hc->expnfilename, hc->hs->cwd, strlen( hc->hs->cwd ) ) == 0 ) /* Elide the current directory. */ (void) strcpy( hc->expnfilename, &hc->expnfilename[strlen( hc->hs->cwd )] ); else if ( hc->altdir[0] != '\0' && ( strncmp( hc->expnfilename, hc->altdir, strlen( hc->altdir ) ) != 0 || ( hc->expnfilename[strlen( hc->altdir )] != '\0' && hc->expnfilename[strlen( hc->altdir )] != '/' ) ) ) { httpd_send_err( hc, 403, err403title, err403form, hc->encodedurl ); return -1; } } hc->accept[0] = '\0'; hc->accepte[0] = '\0'; hc->remoteuser[0] = '\0'; hc->response[0] = '\0'; hc->responselen = 0; hc->referer = ""; hc->useragent = ""; hc->cookie = ""; hc->contenttype = ""; hc->hdrhost = ""; hc->authorization = ""; hc->if_modified_since = (time_t) -1; hc->range_if = (time_t) -1; hc->contentlength = -1; hc->got_range = 0; hc->init_byte_loc = 0; hc->end_byte_loc = -1; hc->keep_alive = 0; if ( hc->mime_flag ) { /* Read the MIME headers. */ while ( ( buf = bufgets( hc ) ) != (char*) 0 ) { if ( buf[0] == '\0' ) break; if ( strncasecmp( buf, "Referer:", 8 ) == 0 ) { cp = &buf[8]; cp += strspn( cp, " \t" ); hc->referer = cp; } else if ( strncasecmp( buf, "User-Agent:", 11 ) == 0 ) { cp = &buf[11]; cp += strspn( cp, " \t" ); hc->useragent = cp; } else if ( strncasecmp( buf, "Host:", 5 ) == 0 ) { cp = &buf[5]; cp += strspn( cp, " \t" ); hc->hdrhost = cp; } else if ( strncasecmp( buf, "Accept:", 7 ) == 0 ) { cp = &buf[7]; cp += strspn( cp, " \t" ); if ( hc->accept[0] != '\0' ) { if ( strlen( hc->accept ) > 5000 ) { syslog( LOG_ERR, "%.80s way too much Accept: data", inet_ntoa( hc->client_addr ) ); continue; } realloc_str( &hc->accept, &hc->maxaccept, strlen( hc->accept ) + 2 + strlen( cp ) ); (void) strcat( hc->accept, ", " ); } else realloc_str( &hc->accept, &hc->maxaccept, strlen( cp ) ); (void) strcat( hc->accept, cp ); } else if ( strncasecmp( buf, "Accept-Encoding:", 16 ) == 0 ) { cp = &buf[16]; cp += strspn( cp, " \t" ); if ( hc->accepte[0] != '\0' ) { if ( strlen( hc->accepte ) > 5000 ) { syslog( LOG_ERR, "%.80s way too much Accept-Encoding: data", inet_ntoa( hc->client_addr ) ); continue; } realloc_str( &hc->accepte, &hc->maxaccepte, strlen( hc->accepte ) + 2 + strlen( cp ) ); (void) strcat( hc->accepte, ", " ); } else realloc_str( &hc->accepte, &hc->maxaccepte, strlen( cp ) ); (void) strcpy( hc->accepte, cp ); } else if ( strncasecmp( buf, "If-Modified-Since:", 18 ) == 0 ) { cp = &buf[18]; hc->if_modified_since = tdate_parse( cp ); if ( hc->if_modified_since == (time_t) -1 ) syslog( LOG_DEBUG, "unparsable time: %.80s", cp ); } else if ( strncasecmp( buf, "Cookie:", 7 ) == 0 ) { cp = &buf[7]; cp += strspn( cp, " \t" ); hc->cookie = cp; } else if ( strncasecmp( buf, "Range:", 6 ) == 0 ) { /* Only support %d- and %d-%d, not %d-%d,%d-%d or -%d. */ if ( strchr( buf, ',' ) == (char*) 0 ) { char* cp_dash; cp = strpbrk( buf, "=" ); if ( cp != (char*) 0 ) { cp_dash = strchr( cp + 1, '-' ); if ( cp_dash != (char*) 0 && cp_dash != cp + 1 ) { *cp_dash = '\0'; hc->got_range = 1; hc->init_byte_loc = atol( cp + 1 ); if ( isdigit( (int) cp_dash[1] ) ) hc->end_byte_loc = atol( cp_dash + 1 ); } } } } else if ( strncasecmp( buf, "Range-If:", 9 ) == 0 || strncasecmp( buf, "If-Range:", 9 ) == 0 ) { cp = &buf[9]; hc->range_if = tdate_parse( cp ); if ( hc->range_if == (time_t) -1 ) syslog( LOG_DEBUG, "unparsable time: %.80s", cp ); } else if ( strncasecmp( buf, "Content-Type:", 13 ) == 0 ) { cp = &buf[13]; cp += strspn( cp, " \t" ); hc->contenttype = cp; } else if ( strncasecmp( buf, "Content-Length:", 15 ) == 0 ) { cp = &buf[15]; hc->contentlength = atol( cp ); } else if ( strncasecmp( buf, "Authorization:", 14 ) == 0 ) { cp = &buf[14]; cp += strspn( cp, " \t" ); hc->authorization = cp; } else if ( strncasecmp( buf, "Connection:", 11 ) == 0 ) { cp = &buf[11]; cp += strspn( cp, " \t" ); if ( strcasecmp( cp, "keep-alive" ) == 0 ) hc->keep_alive = 1; }#ifdef LOG_UNKNOWN_HEADERS else if ( strncasecmp( buf, "Accept-Charset:", 15 ) == 0 || strncasecmp( buf, "Accept-Language:", 16 ) == 0 || strncasecmp( buf, "Agent:", 6 ) == 0 || strncasecmp( buf, "Cache-Control:", 14 ) == 0 || strncasecmp( buf, "Cache-Info:", 11 ) == 0 || strncasecmp( buf, "Charge-To:", 10 ) == 0 || strncasecmp( buf, "Client-ip:", 10 ) == 0 || strncasecmp( buf, "Date:", 5 ) == 0 || strncasecmp( buf, "Extension:", 10 ) == 0 || strncasecmp( buf, "Forwarded:", 10 ) == 0 || strncasecmp( buf, "From:", 5 ) == 0 || strncasecmp( buf, "HTTP-Version:", 13 ) == 0 || strncasecmp( buf, "Message-ID:", 11 ) == 0 || strncasecmp( buf, "MIME-Version:", 13 ) == 0 || strncasecmp( buf, "Negotiate:", 10 ) == 0 || strncasecmp( buf, "Pragma:", 7 ) == 0 || strncasecmp( buf, "Proxy-agent:", 12 ) == 0 || strncasecmp( buf, "Proxy-Connection:", 17 ) == 0 || strncasecmp( buf, "Security-Scheme:", 16 ) == 0 || strncasecmp( buf, "Session-ID:", 11 ) == 0 || strncasecmp( buf, "UA-color:", 9 ) == 0 || strncasecmp( buf, "UA-CPU:", 7 ) == 0 || strncasecmp( buf, "UA-Disp:", 8 ) == 0 || strncasecmp( buf, "UA-OS:", 6 ) == 0 || strncasecmp( buf, "UA-pixels:", 10 ) == 0 || strncasecmp( buf, "User:", 5 ) == 0 || strncasecmp( buf, "Via:", 4 ) == 0 || strncasecmp( buf, "X-", 2 ) == 0 ) ; /* ignore */ else syslog( LOG_DEBUG, "unknown request header: %.80s", buf );#endif /* LOG_UNKNOWN_HEADERS */ } } if ( hc->one_one ) { /* Check that HTTP/1.1 requests specify a host, as required. */ if ( hc->reqhost[0] == '\0' && hc->hdrhost[0] == '\0' ) { httpd_send_err( hc, 400, httpd_err400title, httpd_err400form, "" ); return -1; } /* This is where we would check that the host specified is the ** host we're serving. However, since we still only support one ** virtual host per thttpd process, it's not currently possible ** to use thttpd to serve the new HTTP/1.1-style CNAME-only ** virtual hosts. Therefore, why bother checking for the correct ** host here? It would just be something for the admin to screw ** up, with no benefit from getting it right. */ /* If the client wants to do keep-alives, it might also be doing ** pipelining. There's no way for us to tell. Since we don't ** implement keep-alives yet, if we close such a connection there ** might be unread pipelined requests waiting. So, we have to ** do a lingering close. */ if ( hc->keep_alive ) hc->should_linger = 1; } return 0; }static char*bufgets( httpd_conn* hc ) { int i; char c; for ( i = hc->checked_idx; hc->checked_idx < hc->read_idx; ++hc->checked_idx ) { c = hc->read_buf[hc->checked_idx]; if ( c == '\n' || c == '\r' ) { hc->read_buf[hc->checked_idx] = '\0'; ++hc->checked_idx; if ( c == '\r' && hc->checked_idx < hc->read_idx && hc->read_buf[hc->checked_idx] == '\n' ) { hc->read_buf[hc->checked_idx] = '\0'; ++hc->checked_idx; } return &(hc->read_buf[i]); } } return (char*) 0; }voidhttpd_close_conn( httpd_conn* hc, struct timeval* nowP ) { if ( hc->file_address != (char*) 0 ) { mmc_unmap( hc->file_address, nowP ); hc->file_address = (char*) 0; } if ( hc->conn_fd >= 0 ) { (void) close( hc->conn_fd ); hc->conn_fd = -1; } }voidhttpd_destroy_conn( httpd_conn* hc ) { if ( hc->initialized ) { free( (void*) hc->decodedurl ); free( (void*) hc->origfilename ); free( (void*) hc->expnfilename ); free( (void*) hc->encodings ); free( (void*) hc->pathinfo ); free( (void*) hc->query ); free( (void*) hc->altdir ); free( (void*) hc->accept ); free( (void*) hc->accepte ); free( (void*) hc->reqhost ); free( (void*) hc->remoteuser ); free( (void*) hc->response ); hc->initialized = 0; } }/* Figures out MIME encodings and type based on the filename. Multiple** encodings are separated by semicolons.*/static voidfigure_mime( httpd_conn* hc ) { int i, j, k, l; int got_enc; struct table { char* ext; char* val; }; static struct table enc_tab[] = {#include "mime_encodings.h" }; static struct table typ_tab[] = {#include "mime_types.h" }; /* Look at the extensions on hc->expnfilename from the back forwards. */ hc->encodings[0] = '\0'; i = strlen( hc->expnfilename ); for (;;) { j = i; for (;;) { --i; if ( i <= 0 ) { /* No extensions left. */ hc->type = "text/plain"; return; } if ( hc->expnfilename[i] == '.' ) break; } /* Found an extension. */ got_enc = 0; for ( k = 0; k < sizeof(enc_tab)/sizeof(*enc_tab); ++k ) { l = strlen( enc_tab[k].ext ); if ( l == j - i - 1 && strncasecmp( &hc->expnfilename[i+1], enc_tab[k].ext, l ) == 0 ) { realloc_str( &hc->encodings, &hc->maxencodings, strlen( enc_tab[k].val ) + 1 ); if ( hc->encodings[0] != '\0' ) (void) strcat( hc->encodings, ";" ); (void) strcat( hc->encodings, enc_tab[k].val ); got_enc = 1; } } if ( ! got_enc ) { /* No encoding extension found - time to try type extensions. */ for ( k = 0; k < sizeof(typ_tab)/sizeof(*typ_tab); ++k ) { l = strlen( typ_tab[k].ext ); if ( l == j - i - 1 && strncasecmp( &hc->expnfilename[i+1], typ_tab[k].ext, l ) == 0 ) { hc->type = typ_tab[k].val; return; } } /* No recognized type extension found - return default. */ hc->type = "text/plain"; return; } } }#ifdef CGI_TIMELIMITstatic voidcgi_kill2( ClientData client_data, struct timeval* nowP ) { pid_t pid; pid = (pid_t) client_data.i; if ( kill( pid, SIGKILL ) == 0 ) syslog( LOG_ERR, "hard-killed CGI process %d", pid ); }static voidcgi_kill( ClientData client_data, struct timeval* nowP ) { pid_t pid; /* Before trying to kill the CGI process, reap any zombie processes. ** That may get rid of the CGI process. */ (void) do_reap(); pid = (pid_t) client_data.i; if ( kill( pid, SIGINT ) == 0 ) { syslog( LOG_ERR, "killed CGI process %d", pid ); /* In case this isn't enough, schedule an uncatchable kill. */ (void) tmr_create( nowP, cgi_kill2, client_data, 5 * 1000L, 0 ); } }#endif /* CGI_TIMELIMIT */#ifdef GENERATE_INDEXES/* qsort comparison routine - declared old-style on purpose, for portability. */static intname_compare( a, b ) char** a; char** b; { return strcmp( *a, *b ); }static off_tls( httpd_conn* hc ) { DIR* dirp; struct dirent* de; int namlen; static int maxnames = 0; int nnames; static char* names; static char** nameptrs; static char* name; static int maxname = 0; static char* rname; static int maxrname = 0; FILE* fp; int i, r; struct stat sb; struct stat lsb; char modestr[20]; char* linkprefix; char link[MAXPATHLEN]; int linklen; char* fileclass; time_t now; char* timestr; ClientData client_data; dirp = opendir( hc->expnfilename ); if ( dirp == (DIR*) 0 ) { syslog( LOG_ERR, "opendir %.80s - %m", hc->expnfilename ); httpd_send_err( hc, 404, err404title, err404form, hc->encodedurl ); return -1; } send_mime( hc, 200, ok200title, "", "", "text/html", -1, hc->sb.st_mtime ); hc->bytes = 0; if ( hc->method == METHOD_HEAD ) closedir( dirp ); else if ( hc->method == METHOD_GET ) { httpd_write_response( hc );#ifdef EMBED r = vfork( );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -