⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpdav.c

📁 站点映像程序
💻 C
📖 第 1 页 / 共 5 页
字号:
    }}/* Deal with the body size */int http_req_bodysize( http_req_t *req ) {    struct stat bodyst;    /* Do extra stuff if we have a body */    switch( req->body ) {    case http_body_file:	/* Get file length */	if( fstat( fileno(req->body_file), &bodyst ) < 0 ) {	    /* Stat failed */	    DEBUG( DEBUG_HTTP, "Stat failed: %s\n", strerror( errno ) );	    return PROTO_ERROR;	}	req->body_size = bodyst.st_size;	break;    case http_body_buffer:	req->body_size = strlen( req->body_buffer );	break;    default:	/* No body, so no size. */	return PROTO_OK;    }    if( req->body != http_body_none ) {	char tmp[BUFSIZ];	/* Add the body length header */	snprintf( tmp, BUFSIZ, "Content-Length: %d" EOL, req->body_size );	strcat( req->headers, tmp );    }    return PROTO_OK;}void http_strcat_hostname( struct proto_host_t *host, char *str ) {    strcat( str, host->hostname );    /* Only add the port if it isn't 80 */    if( host->port != HTTP_PORT ) {	static char buffer[128];	snprintf( buffer, 128, ":%d", host->port );	strcat( str, buffer );    }}/* Lob the User-Agent, connection and host headers in to the request * headers */void http_req_fixedheaders( http_req_t *req ) {    strcat( req->headers, "User-Agent: " );    strcat( req->headers, http_useragent );    strcat( req->headers, EOL 	    "Connection: Keep-Alive" EOL 	    "Host: " );    http_strcat_hostname( &http_server_host, req->headers );    strcat( req->headers, EOL );}/* Decodes a URI */char *uri_decode( const char *uri ) {    const char *pnt;    char *ret, *retpos, buf[5] = { "0x00\0" };    retpos = ret = malloc( strlen( uri ) + 1 );    for( pnt = uri; *pnt != '\0'; pnt++ ) {	if( *pnt == '%' ) {	    if( !isxdigit((unsigned char) pnt[1]) || 		!isxdigit((unsigned char) pnt[2]) ) {		/* Invalid URI */		return NULL;	    }	    buf[2] = *++pnt; buf[3] = *++pnt; /* bit faster than memcpy */	    *retpos++ = strtol( buf, NULL, 16 );	} else {	    *retpos++ = *pnt;	}    }    *retpos = '\0';    return ret;}/* RFC2396 spake: * "Data must be escaped if it does not have a representation  * using an unreserved character". * ...where... *  unreserved  = alphanum | mark *  mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" *  * We need also to skip reserved characters * reserved    = ";" | "/" | "?" | ":" | "@" | "&" | *               "=" | "+" | "$" | "," *//* Lookup table: * 1 marks an RESERVED character. 2 marks a UNRESERVED character. * 0 marks everything else.  */#define RE 1#define UN 2 const short uri_chars[128] = {/* 0 */  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 16 */  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 32 */  0, UN, 0, 0, RE, 0, RE, UN, UN, UN, UN, RE, RE, UN, UN, RE,/* 48 */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, RE, RE, 0, RE, 0, RE,/* 64 */ RE, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN,/* 80 */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, 0, 0, 0, 0, UN,/* 96 */ 0, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN,/* 112 */ UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, UN, 0, 0, 0, UN, 0 };#undef RE#undef UN/* Encodes the abspath segment of a URI. * TODO: Make this parse a complete URI */char *uri_abspath_encode( const char *abs_path ) {    const char *pnt;    char *ret, *retpos;    /* Rather than mess about growing the buffer, allocate as much as     * the URI could possibly need, i.e. every character gets %XX     * escaped. Hence 3 times input size.      */    retpos = ret = malloc( strlen( abs_path ) * 3 + 1 );    for( pnt = abs_path; *pnt != '\0'; pnt++ ) {	/* Escape it:	 *  - if it isn't 7-bit	 *  - if it is a reserved character (but ignore '/')	 *  - otherwise, if it is not an unreserved character	 * (note, there are many characters that are neither reserved	 * nor unreserved)	 */	if( *pnt<0 || (uri_chars[(int) *pnt] < 2 && *pnt!='/' )) {	    /* Escape it - %<hex><hex> */	    sprintf( retpos, "%%%02x", (unsigned char) *pnt );	    retpos += 3;	} else {	    /* It's cool */	    *retpos++ = *pnt;	}    }    *retpos = '\0';    return ret;}#ifdef URITESTvoid fe_transfer_progress( size_t progress, size_t total ) {}int main( int argc, char *argv[] ) {    char *tmp;    if( argc!=2 ) {	printf( "doh. usage:\nuritest a_uri_abspath_segment\n"		"e.g. uritest \"/this/is/a silly<filename>/but/hey\"\n" );	exit(-1);    }    printf( "Input URI: %s\n", argv[1] );    tmp = uri_abspath_encode( argv[1] );    printf( "Encoded: %s\n", tmp );    printf( "Decoded: %s\n", uri_decode( tmp ) );    return 0;}#endif /* URITEST *//* Initializes the request with given method and URI. * URI must be abs_path - i.e., NO scheme+hostname. It will BREAK  * otherwise. */void http_request_init( http_req_t *req, 			const char *method, const char *uri ) {    /* Clear it out */    memset( req, 0, sizeof( http_req_t ) );    DEBUG( DEBUG_HTTP, "Request starts.\n" );    /* Add in the fixed headers */    http_req_fixedheaders( req );    /* Set the standard stuff */    req->method = method;    req->uri = uri_abspath_encode( uri );        req->body_callback = NULL;    req->body = http_body_none;    }void http_request_end( http_req_t *req ) {    if( req->uri != NULL ) {	free( req->uri );    }    DEBUG( DEBUG_HTTP, "Request ends.\n" );}/* Reads a block of the response into buffer, which is of size buflen. * Returns number of bytes read, 0 on end-of-response, or -1 on error. */int http_response_read( http_req_t *req, char *buffer, size_t buflen ) {    int willread, readlen;    if( req->resp_te==http_te_chunked ) {	/* We are doing a chunked transfer-encoding.	 * It goes:  `SIZE CRLF CHUNK CRLF SIZE CRLF CHUNK CRLF ...'	 * ended by a `CHUNK CRLF 0 CRLF', a 0-sized chunk.	 * The slight complication is that we have to cope with	 * partial reads of chunks.	 * For this reason, resp_chunk_left contains the number of	 * bytes left to read in the current chunk.	 */	if( req->resp_chunk_left == 0 ) {	    /* We are at the start of a new chunk. */	    DEBUG( DEBUG_HTTP, "New chunk.\n" );	    if( read_line( http_sock, buffer, buflen ) < 0 ) {		DEBUG( DEBUG_HTTP, "Could not read chunk size.\n" );		return -1;	    }	    DEBUG( DEBUG_HTTP, "[Chunk Size] < %s", buffer );	    if( sscanf( buffer, "%x", &req->resp_chunk_left ) != 1 ) {		DEBUG( DEBUG_HTTP, "Couldn't read chunk size.\n" );		return -1;	    }	    DEBUG( DEBUG_HTTP, "Got chunk size: %d\n", req->resp_chunk_left );	    if( req->resp_chunk_left == 0 ) {		/* Zero-size chunk */		DEBUG( DEBUG_HTTP, "Zero-size chunk.\n" );		return 0;	    }	}	willread = min( buflen - 1, req->resp_chunk_left );    } else if( req->resp_length > 0 ) {	/* Have we finished reading the body? */	if( req->resp_left == 0 )	    return 0;	willread = min( buflen - 1, req->resp_left );    } else {	/* Read until socket-close */	willread = buflen - 1;    }    DEBUG( DEBUG_HTTP, "Reading %d bytes of response body.\n", willread );    readlen = sock_read( http_sock, buffer, willread );    DEBUG( DEBUG_HTTP, "Got %d bytes.\n", readlen );    if( readlen < 0 ) {	/* It broke */	DEBUG( DEBUG_HTTP, "Could not read block.\n" );	return -1;    } else if( (readlen == 0) && 	       ( (req->resp_length > 0) ||		 (req->resp_te==http_te_chunked) )) {	/* Premature close before read all of body, or during chunk read. */	DEBUG( DEBUG_HTTP, "Socket closed before end of body.\n" );	return -1;    }    buffer[readlen] = '\0';    DEBUG( DEBUG_HTTP, "Read block:\n%s\n", buffer );    if( req->resp_te==http_te_chunked ) {	req->resp_chunk_left -= readlen;	if( req->resp_chunk_left == 0 ) {	    char crlfbuf[2];	    /* If we've read a whole chunk, read a CRLF */	    if( read_data( http_sock, crlfbuf, 2 ) == 0 ) {		DEBUG( DEBUG_HTTP, "Read CRLF bytes.\n" );		if( strncmp( crlfbuf, EOL, 2 ) != 0 ) {		    DEBUG( DEBUG_HTTP, "CRLF bytes didn't contain CRLF!\n" );		    return -1;		}	    } else {		return -1;	    }	}		    } else if( req->resp_length > 0 ) {	req->resp_left -= readlen;    }    return readlen;}/* The HTTP/1.x request/response mechanism  * * Returns: *   PROTO_OK if the request was made (not related to status code) *   PROTO_ERROR if the request could not be made * The STATUS CODE is placed in req->status. The error string is * placed in http_error. *  * TODO: This should be chopped up into smaller chunks, and get rid of * the horrid goto's.   */int http_request( http_req_t *req ) {    char buffer[BUFSIZ]; /* For reading from the socket */    int ret, attempt, con_attempt;    bool using_expect, /* whether we have sent a Expect: 100 header */	close_connection,	dead_connection,	wants_body; /* whether the caller wants the response body		     * callbacks */#ifdef USE_BROKEN_PROPFIND    bool is_propfind = (strcmp( req->method, "PROPFIND" ) == 0);#endif#define HTTP_FATAL_ERROR(a) {				\	DEBUG( DEBUG_HTTP, a );					\	ret = PROTO_ERROR;					\	close_connection = true;				\	goto http_request_finish_proc;				\    }    /* Initialization... */    DEBUG( DEBUG_HTTP, "Request started...\n" );    strcpy( http_error, "Unknown error." );    ret = PROTO_OK;    if( http_req_bodysize( req ) != PROTO_OK )	return PROTO_ERROR;    /* I shall try this only twice...     * First time, with default authentication stuff (either, what we     * did last time, or none at all), then with up-to-the-minute     * what-the-server-requested authentication stuff. */    attempt = con_attempt = 1;    http_auth_new_request( &http_server_auth, req->method, req->uri,			   req->body_buffer, req->body_file );    do {	char request[REQSIZ], *authinfo = NULL;	/* Add in the Request-Line */	strcpy( request, req->method );	if( http_use_proxy ) {	    strcat( request, " http://" );	    http_strcat_hostname( &http_server_host, request );	} else {	    strcat( request, " " );	}	strcat( request, req->uri );	strcat( request, " HTTP/1.1" EOL );	/* The caller-supplied headers */	strcat( request, req->headers );	if( http_can_authenticate ) {	    /* Add the authorization headers in */	    char *val = http_auth_request( &http_server_auth );	    if( val != NULL ) {		strcat( request, "Authorization: " );		strcat( request, val );		free( val );	    } else {		DEBUG( DEBUG_HTTP, "auth_request returned NULL.\n" );	    }	}	/* Now handle the body. */	using_expect = false;	if( req->body!=http_body_none ) {	    if( (http_expect_works > -1) &&		(req->body_size > HTTP_EXPECT_MINSIZE) #ifdef USE_BROKEN_PROPFIND		/* ... definitely NOT if we're doing PROPFIND */		&& (!is_propfind)#endif /* USE_BROKEN_PROPFIND */		) {		/* Add Expect: 100-continue. */		strcat( request, "Expect: 100-continue" EOL );		using_expect = true;	    }	}	/* Final CRLF */	strcat( request, EOL );		/* Now send the request */	/* Open the connection if necessary */	if( !http_connected ) {	    if( (ret = http_open()) != PROTO_OK )		return ret;	}	dead_connection = false;#ifdef USE_BROKEN_PROPFIND	if( !is_propfind ) {#endif	/* Send the headers */#ifdef DEBUGGING	if( (256&debug_mask) == 256 ) { 	    /* Display everything mode */	    DEBUG( DEBUG_HTTP, "Sending request headers:\n%s", request );	} else {	    /* Blank out the Authorization paramaters */	    char reqdebug[REQSIZ], *pnt;	    strcpy( reqdebug, request );	    pnt = strstr( reqdebug, "Authorization: " );	    if( pnt != NULL ) {		for( pnt += 15; *pnt != '\r' && *pnt != '\0'; pnt++ ) {		    *pnt = 'x';		}	    }	    DEBUG( DEBUG_HTTP, "Sending request headers:\n%s", reqdebug );	}#endif DBEUGGING	if( send_string( http_sock, request ) < 0 ) {	    dead_connection = true;	    HTTP_FATAL_ERROR( "Could not send request!\n" );	}	DEBUG( DEBUG_HTTP, "Request sent.\n" );	#ifdef USE_BROKEN_PROPFIND	}#endif /* USE_BROKEN_PROPFIND */	/* Now, if we are doing a Expect: 100, hang around for a short	 * amount of time, to see if the server actually cares about the 	 * Expect and sends us a 100 Continue response if the request	 * is valid, else an error code if it's not. This saves sending	 * big files to the server when they will be rejected.	 */		if( using_expect ) {	    DEBUG( DEBUG_HTTP, "Waiting for response...\n" );	    ret = sock_block( http_sock, HTTP_EXPECT_TIMEOUT );	    switch( ret ) {	    case -1: /* error */		HTTP_FATAL_ERROR( "Wait (select) failed.\n" );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -