📄 libhttpd.c.bak
字号:
r = vfork( );#else r = fork( );#endif if ( r < 0 ) { syslog( LOG_ERR, "fork - %m" ); httpd_send_err( hc, 500, err500title, err500form, hc->encodedurl ); return -1; } if ( r == 0 ) { /* Child process. */#ifdef CGI_NICE /* Set priority. */ (void) nice( CGI_NICE );#endif /* CGI_NICE */ /* Open a stdio stream so that we can use fprintf, which is more ** efficient than a bunch of separate write()s. We don't have ** to worry about double closes or file descriptor leaks cause ** we're in a subprocess. */ fp = fdopen( hc->conn_fd, "w" ); if ( fp == (FILE*) 0 ) { syslog( LOG_ERR, "fdopen - %m" ); httpd_send_err( hc, 500, err500title, err500form, hc->encodedurl ); closedir( dirp ); return -1; } (void) fprintf( fp, "\<HTML><HEAD><TITLE>Index of %.80s</TITLE></HEAD>\n\<BODY>\n\<H2>Index of %.80s</H2>\n\<PRE>\n\mode links bytes last-changed name\n\<HR>", hc->encodedurl, hc->encodedurl ); /* Read in names. */ nnames = 0; while ( ( de = readdir( dirp ) ) != 0 ) /* dirent or direct */ { if ( nnames >= maxnames ) { if ( maxnames == 0 ) { maxnames = 100; names = NEW( char, maxnames * MAXPATHLEN ); nameptrs = NEW( char*, maxnames ); } else { maxnames *= 2; names = RENEW( names, char, maxnames * MAXPATHLEN ); nameptrs = RENEW( nameptrs, char*, maxnames ); } if ( names == (char*) 0 || nameptrs == (char**) 0 ) { syslog( LOG_ERR, "out of memory" ); exit( 1 ); } for ( i = 0; i < maxnames; ++i ) nameptrs[i] = &names[i * MAXPATHLEN]; } namlen = NAMLEN(de); (void) strncpy( nameptrs[nnames], de->d_name, namlen ); nameptrs[nnames][namlen] = '\0'; ++nnames; } closedir( dirp ); /* Sort the names. */ qsort( nameptrs, nnames, sizeof(*nameptrs), name_compare ); /* Generate output. */ for ( i = 0; i < nnames; ++i ) { realloc_str( &name, &maxname, strlen( hc->expnfilename ) + 1 + strlen( nameptrs[i] ) ); realloc_str( &rname, &maxrname, strlen( hc->origfilename ) + 1 + strlen( nameptrs[i] ) ); if ( hc->expnfilename[0] == '\0' || strcmp( hc->expnfilename, "." ) == 0 ) { (void) strcpy( name, nameptrs[i] ); (void) strcpy( rname, nameptrs[i] ); } else { (void) sprintf( name, "%s/%s", hc->expnfilename, nameptrs[i] ); (void) sprintf( rname, "%s%s", hc->origfilename, nameptrs[i] ); } if ( stat( name, &sb ) < 0 || lstat( name, &lsb ) < 0 ) continue; linkprefix = ""; link[0] = '\0'; /* Break down mode word. First the file type. */ switch ( lsb.st_mode & S_IFMT ) { case S_IFIFO: modestr[0] = 'p'; break; case S_IFCHR: modestr[0] = 'c'; break; case S_IFDIR: modestr[0] = 'd'; break; case S_IFBLK: modestr[0] = 'b'; break; case S_IFREG: modestr[0] = '-'; break; case S_IFSOCK: modestr[0] = 's'; break; case S_IFLNK: modestr[0] = 'l'; linklen = readlink( name, link, sizeof(link) ); if ( linklen != -1 ) { link[linklen] = '\0'; linkprefix = " -> "; } break; default: modestr[0] = '?'; break; } /* Now the world permissions. Owner and group permissions ** are not of interest to web clients. */ modestr[1] = ( lsb.st_mode & S_IROTH ) ? 'r' : '-'; modestr[2] = ( lsb.st_mode & S_IWOTH ) ? 'w' : '-'; modestr[3] = ( lsb.st_mode & S_IXOTH ) ? 'x' : '-'; modestr[4] = '\0'; /* We also leave out the owner and group name, they are ** also not of interest to web clients. Plus if we're ** running under chroot(), they would require a copy ** of /etc/passwd and /etc/group, which we want to avoid. */ /* Get time string. */ now = time( (time_t*) 0 ); timestr = ctime( &lsb.st_mtime ); timestr[ 0] = timestr[ 4]; timestr[ 1] = timestr[ 5]; timestr[ 2] = timestr[ 6]; timestr[ 3] = ' '; timestr[ 4] = timestr[ 8]; timestr[ 5] = timestr[ 9]; timestr[ 6] = ' '; if ( now - lsb.st_mtime > 60*60*24*182 ) /* 1/2 year */ { timestr[ 7] = ' '; timestr[ 8] = timestr[20]; timestr[ 9] = timestr[21]; timestr[10] = timestr[22]; timestr[11] = timestr[23]; } else { timestr[ 7] = timestr[11]; timestr[ 8] = timestr[12]; timestr[ 9] = ':'; timestr[10] = timestr[14]; timestr[11] = timestr[15]; } timestr[12] = '\0'; /* The ls -F file class. */ switch ( sb.st_mode & S_IFMT ) { case S_IFDIR: fileclass = "/"; break; case S_IFSOCK: fileclass = "="; break; case S_IFLNK: fileclass = "@"; break; default: fileclass = ( sb.st_mode & S_IXOTH ) ? "*" : ""; break; } /* And print. */ (void) fprintf( fp, "%s %3ld %8ld %s <A HREF=\"/%.500s%s\">%.80s</A>%s%s%s\n", modestr, (long) lsb.st_nlink, (long) lsb.st_size, timestr, rname, S_ISDIR(sb.st_mode) ? "/" : "", nameptrs[i], linkprefix, link, fileclass ); } (void) fprintf( fp, "</PRE></BODY></HTML>\n" ); (void) fclose( fp ); exit( 0 ); } /* Parent process. */ closedir( dirp );#ifdef CGI_TIMELIMIT /* Schedule a kill for the child process, in case it runs too long */ client_data.i = r; (void) tmr_create( (struct timeval*) 0, cgi_kill, client_data, CGI_TIMELIMIT * 1000L, 0 );#endif /* CGI_TIMELIMIT */ hc->status = 200; hc->bytes = CGI_BYTECOUNT; } else { httpd_send_err( hc, 501, err501title, err501form, httpd_method_str( hc->method ) ); return -1; } return 0; }#endif /* GENERATE_INDEXES */static char*build_env( char* fmt, char* arg ) { char* cp; int size; static char* buf; static int maxbuf = 0; size = strlen( fmt ) + strlen( arg ); if ( size > maxbuf ) realloc_str( &buf, &maxbuf, size ); (void) sprintf( buf, fmt, arg ); cp = strdup( buf ); if ( cp == (char*) 0 ) { syslog( LOG_ERR, "out of memory" ); exit( 1 ); } return cp; }#ifdef SERVER_NAME_LISTstatic char*hostname_map( char* hostname ) { int len, n; static char* list[] = { SERVER_NAME_LIST }; len = strlen( hostname ); for ( n = sizeof(list) / sizeof(*list) - 1; n >= 0; --n ) if ( strncasecmp( hostname, list[n], len ) == 0 ) if ( list[n][len] == '/' ) /* check in case of a substring match */ return &list[n][len + 1]; return (char*) 0; }#endif /* SERVER_NAME_LIST *//* Set up environment variables. Be real careful here to avoid** letting malicious clients overrun a buffer. We don't have** to worry about freeing stuff since we're a sub-process.*/static char**make_envp( httpd_conn* hc ) { static char* envp[50]; int envn; char* cp; char buf[256]; envn = 0; envp[envn++] = build_env( "PATH=%s", CGI_PATH ); envp[envn++] = build_env( "SERVER_SOFTWARE=%s", SERVER_SOFTWARE ); cp = hc->hs->hostname;#ifdef SERVER_NAME_LIST if ( cp == (char*) 0 && gethostname( buf, sizeof(buf) ) >= 0 ) cp = hostname_map( buf );#endif /* SERVER_NAME_LIST */ if ( cp == (char*) 0 ) {#ifdef SERVER_NAME cp = SERVER_NAME;#else /* SERVER_NAME */ if ( gethostname( buf, sizeof(buf) ) >= 0 ) cp = buf;#endif /* SERVER_NAME */ } if ( cp != (char*) 0 ) envp[envn++] = build_env( "SERVER_NAME=%s", cp ); envp[envn++] = "GATEWAY_INTERFACE=CGI/1.1"; envp[envn++] = build_env("SERVER_PROTOCOL=%s", hc->protocol); (void) sprintf( buf, "%d", hc->hs->port ); envp[envn++] = build_env( "SERVER_PORT=%s", buf ); envp[envn++] = build_env( "REQUEST_METHOD=%s", httpd_method_str( hc->method ) ); if ( hc->pathinfo[0] != '\0' ) { char* cp2; envp[envn++] = build_env( "PATH_INFO=/%s", hc->pathinfo ); cp2 = NEW( char, strlen( hc->hs->cwd ) + strlen( hc->pathinfo ) ); if ( cp2 != (char*) 0 ) { (void) sprintf( cp2, "%s%s", hc->hs->cwd, hc->pathinfo ); envp[envn++] = build_env( "PATH_TRANSLATED=%s", cp2 ); } } envp[envn++] = build_env( "SCRIPT_NAME=/%s", hc->origfilename ); if ( hc->query[0] != '\0') envp[envn++] = build_env( "QUERY_STRING=%s", hc->query ); envp[envn++] = build_env( "REMOTE_ADDR=%s", inet_ntoa( hc->client_addr ) ); if ( hc->referer[0] != '\0' ) envp[envn++] = build_env( "HTTP_REFERER=%s", hc->referer ); if ( hc->useragent[0] != '\0' ) envp[envn++] = build_env( "HTTP_USER_AGENT=%s", hc->useragent ); if ( hc->accept[0] != '\0' ) envp[envn++] = build_env( "HTTP_ACCEPT=%s", hc->accept ); if ( hc->accepte[0] != '\0' ) envp[envn++] = build_env( "HTTP_ACCEPT_ENCODING=%s", hc->accepte ); if ( hc->cookie[0] != '\0' ) envp[envn++] = build_env( "HTTP_COOKIE=%s", hc->cookie ); if ( hc->contenttype[0] != '\0' ) envp[envn++] = build_env( "CONTENT_TYPE=%s", hc->contenttype ); if ( hc->contentlength != -1 ) { (void) sprintf( buf, "%ld", (long) hc->contentlength ); envp[envn++] = build_env( "CONTENT_LENGTH=%s", buf ); } if ( hc->remoteuser[0] != '\0' ) envp[envn++] = build_env( "REMOTE_USER=%s", hc->remoteuser ); if ( getenv( "TZ" ) != (char*) 0 ) envp[envn++] = build_env( "TZ=%s", getenv( "TZ" ) ); envp[envn] = (char*) 0; return envp; }/* Set up argument vector. Again, we don't have to worry about freeing stuff** since we're a sub-process. This gets done after make_envp() because we** scribble on hc->query.*/static char**make_argp( httpd_conn* hc ) { char** argp; int argn; char* cp1; char* cp2; /* By allocating an arg slot for every character in the query, plus ** one for the filename and one for the NULL, we are guaranteed to ** have enough. We could actually use strlen/2. */ argp = NEW( char*, strlen( hc->query ) + 2 ); if ( argp == (char**) 0 ) return (char**) 0; argp[0] = strrchr( hc->expnfilename, '/' ); if ( argp[0] != (char*) 0 ) ++argp[0]; else argp[0] = hc->expnfilename; argn = 1; /* According to the CGI spec at http://hoohoo.ncsa.uiuc.edu/cgi/cl.html, ** "The server should search the query information for a non-encoded = ** character to determine if the command line is to be used, if it finds ** one, the command line is not to be used." */ if ( strchr( hc->query, '=' ) == (char*) 0 ) { for ( cp1 = cp2 = hc->query; *cp2 != '\0'; ++cp2 ) { if ( *cp2 == '+' ) { *cp2 = '\0'; strdecode( cp1, cp1 ); argp[argn++] = cp1; cp1 = cp2 + 1; } } if ( cp2 != cp1 ) { strdecode( cp1, cp1 ); argp[argn++] = cp1; } } argp[argn] = (char*) 0; return argp; }/* This routine is used only for POST requests. It reads the data** from the request and sends it to the child process. The only reason** we need to do it this way instead of just letting the child read** directly is that we have already read part of the data into our** buffer.*/static voidcgi_interpose( httpd_conn* hc, int wfd ) { int c, r; char buf[1024]; printf("CGI interpose\n"); c = hc->read_idx - hc->checked_idx; if ( c > 0 ) { if ( write( wfd, &(hc->read_buf[hc->checked_idx]), c ) < 0 ) exit( -1 ); } while ( c < hc->contentlength ) { r = read( hc->conn_fd, buf, MIN( sizeof(buf), hc->contentlength - c ) ); if ( r == 0 ) sleep( 1 ); else if ( r < 0 ) { if ( errno == EAGAIN ) sleep( 1 ); else exit( -1 ); } else { if ( write( wfd, buf, r ) < 0 ) exit( -1 ); c += r; } } exit( 0 ); }/* CGI child process. */static voidcgi_child( httpd_conn* hc ) { int r; char** argp; char** envp; char http_head[] = "HTTP/1.0 200 OK\n"; char* binary; char* directory; /* Set up stdin. For POSTs we may have to set up a pipe from an ** interposer process, depending on if we've read some of the data ** into our buffer. */printf("CGI child\n"); if ( hc->method == METHOD_POST && hc->read_idx > hc->checked_idx ) { int p[2]; if ( pipe( p ) < 0 ) { syslog( LOG_ERR, "pipe - %m" ); httpd_send_err( hc, 500, err500title, err500form, hc->encodedurl ); exit( 1 ); }#ifdef EMBED r = vfork( );#else r = fork( );#endif if ( r < 0 ) { syslog( LOG_ERR, "fork - %m" ); httpd_send_err( hc, 500, err500title, err500form, hc->encodedurl ); exit( 1 ); } if ( r == 0 ) { /* Interposer process. */ (void) close( p[0] ); cgi_interpose( hc, p[1] ); } (void) close( p[1] ); (void) dup2( p[0], STDIN_FILENO ); } else { /* Otherwise, the request socket is stdin. */ (void) dup2( hc->conn_fd, STDIN_FILENO ); } /* Unset close-on-exec flag for this socket. This actually shouldn't ** be necessary, according to POSIX a dup()'d file descriptor does ** *not* inherit the close-on-exec flag, its flag is always clear. ** However, Linux messes this up and does copy the flag to the ** dup()'d descrip
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -