📄 libhttpd.c.bak
字号:
restlen = strlen( path ); realloc_str( &rest, &maxrest, restlen ); (void) strcpy( rest, path ); if ( rest[restlen - 1] == '/' ) rest[--restlen] = '\0'; /* trim trailing slash */ /* Remove any leading slashes. */ while ( rest[0] == '/' ) { (void) strcpy( rest, &(rest[1]) ); --restlen; } r = rest; nlinks = 0; /* While there are still components to check... */ while ( restlen > 0 ) { /* Save current checkedlen in case we get a symlink. Save current ** restlen in case we get a non-existant component. */ prevcheckedlen = checkedlen; prevrestlen = restlen; /* Grab one component from r and transfer it to checked. */ cp1 = strchr( r, '/' ); if ( cp1 != (char*) 0 ) { i = cp1 - r; if ( i == 0 ) { /* Special case for absolute paths. */ realloc_str( &checked, &maxchecked, checkedlen + 1 ); (void) strncpy( &checked[checkedlen], r, 1 ); checkedlen += 1; } else if ( strncmp( r, "..", MAX( i, 2 ) ) == 0 ) { /* Ignore ..'s that go above the start of the path. */ if ( checkedlen != 0 ) { cp2 = strrchr( checked, '/' ); if ( cp2 == (char*) 0 ) checkedlen = 0; else if ( cp2 == checked ) checkedlen = 1; else checkedlen = cp2 - checked; } } else { realloc_str( &checked, &maxchecked, checkedlen + 1 + i ); if ( checkedlen > 0 && checked[checkedlen-1] != '/' ) checked[checkedlen++] = '/'; (void) strncpy( &checked[checkedlen], r, i ); checkedlen += i; } checked[checkedlen] = '\0'; r += i + 1; restlen -= i + 1; } else { /* No slashes remaining, r is all one component. */ if ( strcmp( r, ".." ) == 0 ) { /* Ignore ..'s that go above the start of the path. */ if ( checkedlen != 0 ) { cp2 = strrchr( checked, '/' ); if ( cp2 == (char*) 0 ) checkedlen = 0; else if ( cp2 == checked ) checkedlen = 1; else checkedlen = cp2 - checked; checked[checkedlen] = '\0'; } } else { realloc_str( &checked, &maxchecked, checkedlen + 1 + restlen ); if ( checkedlen > 0 && checked[checkedlen-1] != '/' ) checked[checkedlen++] = '/'; (void) strcpy( &checked[checkedlen], r ); checkedlen += restlen; } r += restlen; restlen = 0; } /* Try reading the current filename as a symlink */ linklen = readlink( checked, link, sizeof(link) ); if ( linklen == -1 ) { if ( errno == EINVAL ) continue; /* not a symlink */ if ( errno == EACCES || errno == ENOENT || errno == ENOTDIR || errno == EBADF ) { /* That last component was bogus. Restore and return. */ *restP = r - ( prevrestlen - restlen ); if ( prevcheckedlen == 0 ) (void) strcpy( checked, "." ); else checked[prevcheckedlen] = '\0'; return checked; } syslog( LOG_ERR, "readlink %s - (%d) %m", checked, errno ); return (char*) 0; } ++nlinks; if ( nlinks > MAX_LINKS ) { syslog( LOG_ERR, "too many symlinks in %.80s", path ); return (char*) 0; } link[linklen] = '\0'; if ( link[linklen - 1] == '/' ) link[--linklen] = '\0'; /* trim trailing slash */ /* Insert the link contents in front of the rest of the filename. */ if ( restlen != 0 ) { (void) strcpy( rest, r ); realloc_str( &rest, &maxrest, restlen + linklen + 1 ); for ( i = restlen; i >= 0; --i ) rest[i + linklen + 1] = rest[i]; (void) strcpy( rest, link ); rest[linklen] = '/'; restlen += linklen + 1; r = rest; } else { /* There's nothing left in the filename, so the link contents ** becomes the rest. */ realloc_str( &rest, &maxrest, linklen ); (void) strcpy( rest, link ); restlen = linklen; r = rest; } /* Re-check this component. */ checkedlen = prevcheckedlen; checked[checkedlen] = '\0'; } /* Ok. */ *restP = r; if ( checked[0] == '\0' ) (void) strcpy( checked, "." ); return checked; }inthttpd_get_conn( httpd_server* hs, httpd_conn* hc ) { struct sockaddr_in sin; int sz; if ( ! hc->initialized ) { hc->maxdecodedurl = hc->maxorigfilename = hc->maxexpnfilename = hc->maxencodings = hc->maxpathinfo = hc->maxquery = hc->maxaltdir = hc->maxaccept = hc->maxaccepte = hc->maxreqhost = hc->maxremoteuser = hc->maxresponse = 0; realloc_str( &hc->decodedurl, &hc->maxdecodedurl, 1 ); realloc_str( &hc->origfilename, &hc->maxorigfilename, 1 ); realloc_str( &hc->expnfilename, &hc->maxexpnfilename, 0 ); realloc_str( &hc->encodings, &hc->maxencodings, 0 ); realloc_str( &hc->pathinfo, &hc->maxpathinfo, 0 ); realloc_str( &hc->query, &hc->maxquery, 0 ); realloc_str( &hc->altdir, &hc->maxaltdir, 0 ); realloc_str( &hc->accept, &hc->maxaccept, 0 ); realloc_str( &hc->accepte, &hc->maxaccepte, 0 ); realloc_str( &hc->reqhost, &hc->maxreqhost, 0 ); realloc_str( &hc->remoteuser, &hc->maxremoteuser, 0 ); realloc_str( &hc->response, &hc->maxresponse, 0 ); hc->initialized = 1; } /* Accept the new connection. */ sz = sizeof(sin); hc->conn_fd = accept( hs->listen_fd, (struct sockaddr*) &sin, &sz ); if ( hc->conn_fd < 0 ) { if ( errno == EWOULDBLOCK ) return GC_NO_MORE; syslog( LOG_ERR, "accept - %m" ); return GC_FAIL; } (void) fcntl( hc->conn_fd, F_SETFD, 1 ); hc->hs = hs; hc->client_addr = sin.sin_addr; hc->read_idx = 0; hc->checked_idx = 0; hc->checked_state = CHST_FIRSTWORD; hc->protocol = "HTTP/1.0"; hc->mime_flag = 1; hc->should_linger = 0; hc->file_address = (char*) 0; return GC_OK; }/* Checks hc->read_buf to see whether a complete request has been read so far;** either the first line has two words (an HTTP/0.9 request), or the first** line has three words and there's a blank line present.**** hc->read_idx is how much has been read in; hc->checked_idx is how much we** have checked so far; and hc->checked_state is the current state of the** finite state machine.*/inthttpd_got_request( httpd_conn* hc ) { char c; for ( ; hc->checked_idx < hc->read_idx; ++hc->checked_idx ) { c = hc->read_buf[hc->checked_idx]; switch ( hc->checked_state ) { case CHST_FIRSTWORD: switch ( c ) { case ' ': case '\t': hc->checked_state = CHST_FIRSTWS; break; case '\n': case '\r': hc->checked_state = CHST_BOGUS; return GR_BAD_REQUEST; } break; case CHST_FIRSTWS: switch ( c ) { case ' ': case '\t': break; case '\n': case '\r': hc->checked_state = CHST_BOGUS; return GR_BAD_REQUEST; default: hc->checked_state = CHST_SECONDWORD; break; } break; case CHST_SECONDWORD: switch ( c ) { case ' ': case '\t': hc->checked_state = CHST_SECONDWS; break; case '\n': case '\r': /* The first line has only two words - an HTTP/0.9 request. */ return GR_GOT_REQUEST; } break; case CHST_SECONDWS: switch ( c ) { case ' ': case '\t': break; case '\n': case '\r': hc->checked_state = CHST_BOGUS; return GR_BAD_REQUEST; default: hc->checked_state = CHST_THIRDWORD; break; } break; case CHST_THIRDWORD: switch ( c ) { case ' ': case '\t': hc->checked_state = CHST_BOGUS; return GR_BAD_REQUEST; case '\n': hc->checked_state = CHST_LF; break; case '\r': hc->checked_state = CHST_CR; break; } break; case CHST_LINE: switch ( c ) { case '\n': hc->checked_state = CHST_LF; break; case '\r': hc->checked_state = CHST_CR; break; } break; case CHST_LF: switch ( c ) { case '\n': /* Two newlines in a row - a blank line - end of request. */ return GR_GOT_REQUEST; case '\r': hc->checked_state = CHST_CR; break; default: hc->checked_state = CHST_LINE; break; } break; case CHST_CR: switch ( c ) { case '\n': hc->checked_state = CHST_CRLF; break; case '\r': /* Two returns in a row - end of request. */ return GR_GOT_REQUEST; default: hc->checked_state = CHST_LINE; break; } break; case CHST_CRLF: switch ( c ) { case '\n': /* Two newlines in a row - end of request. */ return GR_GOT_REQUEST; case '\r': hc->checked_state = CHST_CRLFCR; break; default: hc->checked_state = CHST_LINE; break; } break; case CHST_CRLFCR: switch ( c ) { case '\n': case '\r': /* Two CRLFs or two CRs in a row - end of request. */ return GR_GOT_REQUEST; default: hc->checked_state = CHST_LINE; break; } break; case CHST_BOGUS: return GR_BAD_REQUEST; } } return GR_NO_REQUEST; }inthttpd_parse_request( httpd_conn* hc ) { char* buf; char* method_str; char* url; char* protocol; char* reqhost; char* eol; char* cp; char* pi; hc->checked_idx = 0; hc->mime_flag = 0; hc->one_one = 0; method_str = bufgets( hc ); url = strpbrk( method_str, " \t\n\r" ); if ( url == (char*) 0 ) { httpd_send_err( hc, 400, httpd_err400title, httpd_err400form, "" ); return -1; } *url++ = '\0'; url += strspn( url, " \t\n\r" ); protocol = strpbrk( url, " \t\n\r" ); if ( protocol == (char*) 0 ) protocol = "HTTP/0.9"; else { *protocol++ = '\0'; protocol += strspn( protocol, " \t\n\r" ); if ( *protocol != '\0' ) { hc->mime_flag = 1; eol = strpbrk( protocol, " \t\n\r" ); if ( eol != (char*) 0 ) *eol = '\0'; if ( strcasecmp( protocol, "HTTP/1.0" ) != 0 ) hc->one_one = 1; } } /* Check for HTTP/1.1 absolute URL. */ if ( strncasecmp( url, "http://", 7 ) == 0 ) { if ( ! hc->one_one ) { httpd_send_err( hc, 400, httpd_err400title, httpd_err400form, "" ); return -1; } reqhost = url + 7; url = strchr( reqhost, '/' ); if ( url == (char*) 0 ) { httpd_send_err( hc, 400, httpd_err400title, httpd_err400form, "" ); return -1; } *url = '\0'; realloc_str( &hc->reqhost, &hc->maxreqhost, strlen( reqhost ) ); (void) strcpy( hc->reqhost, reqhost ); *url = '/'; } else hc->reqhost[0] = '\0'; if ( strcasecmp( method_str, httpd_method_str( METHOD_GET ) ) == 0 ) hc->method = METHOD_GET; else if ( strcasecmp( method_str, httpd_method_str( METHOD_HEAD ) ) == 0 ) hc->method = METHOD_HEAD; else if ( strcasecmp( method_str, httpd_method_str( METHOD_POST ) ) == 0 ) hc->method = METHOD_POST; else { httpd_send_err( hc, 501, err501title, err501form, method_str ); return -1; } hc->encodedurl = url; realloc_str( &hc->decodedurl, &hc->maxdecodedurl, strlen( hc->encodedurl ) ); strdecode( hc->decodedurl, hc->encodedurl ); hc->protocol = protocol; if ( hc->decodedurl[0] != '/' ) { httpd_send_err( hc, 400, httpd_err400title, httpd_err400form, "" ); return -1; } realloc_str( &hc->origfilename, &hc->maxorigfilename, strlen( hc->decodedurl ) ); (void) strcpy( hc->origfilename, &hc->decodedurl[1] ); /* Special case for top-level URL. */ if ( hc->origfilename[0] == '\0' ) (void) strcpy( hc->origfilename, "." ); /* Extract query string from encoded URL. */ hc->query[0] = '\0'; cp = strchr( hc->encodedurl, '?' ); if ( cp != (char*) 0 ) { ++cp; realloc_str( &hc->query, &hc->maxquery, strlen( cp ) ); (void) strcpy( hc->query, cp ); } /* And remove query from filename. */ cp = strchr( hc->origfilename, '?' ); if ( cp != (char*) 0 ) *cp = '\0'; /* Copy original filename to expanded filename. */ realloc_str( &hc->expnfilename, &hc->maxexpnfilename, strlen( hc->origfilename ) ); (void) strcpy( hc->expnfilename, hc->origfilename ); /* Tilde mapping. */ hc->altdir[0] = '\0'; if ( hc->expnfilename[0] == '~' ) { if ( ! tilde_map( hc ) ) { httpd_send_err( hc, 500, err500title, err500form, hc->encodedurl ); return -1; } } /* Expand all symbolic links in the filename. This also gives us ** any trailing non-existing components, for pathinfo. */ cp = expand_symlinks( hc->expnfilename, &pi, hc->hs->chrooted ); if ( cp == (char*) 0 ) { httpd_send_err( hc, 500, err500title, err500form, hc->encodedurl );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -