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

📄 httpdav.c

📁 站点映像程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	DEBUG( DEBUG_XML, "Parse error - not good context for this tag.\n" );	return;    }    /* Now actually do something about it */    switch( s->tag ) {    case dav_xml_response:	/* new file information */	DEBUG( DEBUG_XML, "New file context.\n" );	memset( doc->file, 0, sizeof(struct proto_file_t) );	break;    case dav_xml_href:    case dav_xml_getcontentlength:    case dav_xml_resourcetype:    case dav_xml_getlastmodified:	/* For these elements, collect the CDATA */	DEBUG( DEBUG_XML, "Collecting CDATA...\n" );	doc->want_cdata = true;	break;    case dav_xml_prop:    case dav_xml_propstat:    case dav_xml_collection:    default:	/* donothing */	break;    }    if( doc->want_cdata ) {	/* Ready the cdata buffer for new cdata */	if( doc->cdata_buflen == -1 ) {	    /* Create a buffer */	    DEBUG( DEBUG_XML, "Allocating new cdata buffer.\n" );	    doc->cdata = malloc( CDATABUFSIZ );	    doc->cdata_buflen = CDATABUFSIZ;	}	/* Now zero-out the buffer. */	memset( doc->cdata, 0, doc->cdata_buflen );	/* And we've got nothing in it */	doc->cdata_len = 0;    }}/* Returns the depth of the file in the directory heirarchy, * i.e. 1 for /foo.html, 2 for /bar/norm.html, 4 for /a/b/c/d.html */static int dav_fetch_getdepth( const char *href ) {    const char *pnt;    int count = 0;    for( pnt=href; *pnt != '\0'; pnt++ ) /* oneliner */	if( *pnt == '/' ) count++;    return count;}static bool dav_fetch_parse_href( struct dav_xmldoc *doc ) {    const char *tmp;    char *dec;    bool ret;    size_t rootlen;    DEBUG( DEBUG_HTTP, "Parsing href [%s]\n", doc->cdata );    if( strncmp( doc->cdata, "http://", 7 ) == 0 ) {	/* Absolute URI.	 * Look for the path bit */	DEBUG( DEBUG_HTTP, "Got absolute URI.\n" );	tmp = strchr( doc->cdata+7, '/' );	if( tmp == NULL ) {	    DEBUG( DEBUG_HTTP, "No path segment found.\n" );	    return false;	}    } else {	tmp = doc->cdata;    }    DEBUG( DEBUG_HTTP, "Using abspath segment: %s\n", tmp );    dec = uri_decode( tmp );    DEBUG( DEBUG_HTTP, "Decoded is: [%s]. Root is [%s]\n", tmp,	   doc->fetch_root );    /* Now, dec points to the absPath section of the URI.     * We check whether this resource is actually in the     * collection we have done the PROPFIND against.     */    rootlen = strlen( doc->fetch_root );    if( strncmp( dec, doc->fetch_root, rootlen ) != 0 ) {	DEBUG( DEBUG_HTTP, "parse_href failed: root collection not matched." );	ret = false;    } else {	/* We're in the right place */	DEBUG( DEBUG_HTTP, "parse_href: Got [%s]\n", dec + rootlen );	/* Filename must be the basename */	doc->file->filename = strdup( base_name( dec + rootlen ) );	/* And fill in the directory while we're here */	doc->file->directory = dir_name( dec + rootlen );	ret = true;	DEBUG( DEBUG_HTTP, "parse_href: Filename [%s], Directory [%s]\n",	       doc->file->filename, doc->file->directory );    }    free( dec );    return ret;}static void dav_fetch_gotresource( struct dav_xmldoc *doc ) {    struct proto_file_t *current, *previous;    DEBUG( DEBUG_HTTP, "Got resource:\n"	   "filename = [%s] isdir = %s size = %d mtime = %s\n", 	   doc->file->filename, doc->file->isdir?"true":"false", 	   doc->file->size, rfc1123_date( doc->file->modtime ) );    if( (strlen( doc->file->directory ) == 0) &&	(strlen( doc->file->filename ) == 0 ) ) {	DEBUG( DEBUG_HTTP, "Resource is root collection, ignoring.\n" );	return;    }       if( doc->file->isdir ) {	doc->file->directory[strlen(doc->file->directory)-1] = '\0';    }    DEBUG( DEBUG_HTTP, "Filename is really: %s\n", doc->file->filename );    /* Depth in the hierarchy - i.e., how many directories deep the     * resource is. */    doc->file->depth = dav_fetch_getdepth( doc->file->directory );    DEBUG( DEBUG_HTTP, "File is at depth: %d\n", doc->file->depth );    /* Insert it into the list, keeping the list sorted by depth */    for( current=doc->files, previous=NULL; current!=NULL; 	 previous=current, current=current->next )	/* one-liner */	if( current->depth > doc->file->depth )	    break;    doc->file->next = current;    if( previous == NULL ) {	doc->files = doc->file;    } else {	previous->next = doc->file;    }    /* Create a new file, ready to be filled in */    doc->file = malloc( sizeof( struct proto_file_t ) );    memset( doc->file, 0, sizeof( struct proto_file_t ) );}/* End-of-element handler */static void dav_xml_endelm( void *userdata, const char *tag ) {    struct dav_xmldoc *doc = (struct dav_xmldoc *)userdata;    struct dav_xml_state *s;    dav_xml_ns *this_ns, *next_ns;    if( !doc->valid ) {	/* We've stopped parsing */	DEBUG( DEBUG_XML, "Parse died. Ignoring end of element: %s\n", tag );	return;    }    s = doc->current;    DEBUG( DEBUG_XML, "End of element %s.\n", tag);    switch( s->tag ) {    case dav_xml_href:	doc->valid = dav_fetch_parse_href( doc );	break;    case dav_xml_getlastmodified:	DEBUG( DEBUG_HTTP, "Parsing date [%s]\n", doc->cdata );	doc->file->modtime = rfc1123_parse( doc->cdata );	if( doc->file->modtime == (time_t)-1 ) {	    DEBUG( DEBUG_HTTP, "Date is not in RFC1123 format.\n" );	    doc->valid = false;	}	break;    case dav_xml_getcontentlength:	doc->file->size = atoi( doc->cdata );	break;    case dav_xml_collection:	doc->file->isdir = true;	break;    case dav_xml_response:	dav_fetch_gotresource( doc );	break;    default:	break;    }    /* Move the current pointer up the chain */    doc->current = s->parent;    DEBUG( DEBUG_XML, "Back in tag: %s\n", doc->current->tag_name );    if( doc->want_cdata ) {	/* Free the cdata buffer if it's grown to big for its boots. */	if( doc->cdata_buflen > CDATASHRINK ) {	    DEBUG( DEBUG_XML, "cdata buffer overgrown, freeing.\n" );	    free( doc->cdata );	    doc->cdata_buflen = -1;	} 	/* And we've stopped collecting it now, thanks */	doc->want_cdata = false;    }    if( s->default_ns!=NULL ) free( s->default_ns );    /* Free the namespaces */    this_ns = s->nspaces;    while( this_ns != NULL ) {	next_ns = this_ns->next;	free( this_ns );	this_ns = next_ns;    };    free( s->tag_name );    free( s );    DEBUG( DEBUG_XML, "Cleanup okay.\n" );}/* CDATA handler. We keep the entire cdata for each element in * doc->cdata, and expand the buffer as necessary. */static void dav_xml_cdata( void *userdata, const char *cdata, int len ) {    struct dav_xmldoc *doc = (struct dav_xmldoc *)userdata;    size_t newlen;        if( !doc->want_cdata ) return;    /* First, if this is the beginning of the CDATA, skip all     * leading whitespace, we don't want it. */    if( doc->cdata_buflen < 0  ) {	DEBUG( DEBUG_XML, "ALERT: Shouldn't be collecting.\n" );	return;    }    DEBUG( DEBUG_XML, "Given %d bytes of cdata.\n", len );    if( doc->cdata_len == 0 ) {	size_t wslen = 0;	/* Ignore any leading whitespace */	while( wslen < len && 	       ( cdata[wslen] == ' ' || cdata[wslen] == '\r' ||		 cdata[wslen] == '\n' || cdata[wslen] == '\t' ) ) {	    wslen++;	}	cdata += wslen;	len -= wslen;	DEBUG( DEBUG_XML, "Skipped %d bytes of leading whitespace.\n", 	       wslen );	if( len == 0 ) {	    DEBUG( DEBUG_XML, "Zero bytes of content.\n" );	    return;	}    }    /* Work out whether we need to expand the cdata buffer to     * include the new incoming cdata. We always keep one more     * byte in the buffer than we need, for the null-terminator */    for( newlen = doc->cdata_buflen; 	 newlen < (doc->cdata_len + len + 1);	 newlen += CDATABUFSIZ ) /* nullop */ ;    if( newlen > doc->cdata_buflen ) { 	size_t oldbuflen = doc->cdata_buflen;	/* Reallocate bigger buffer */	DEBUG( DEBUG_XML, "Growing CDATA buffer from %d to %d.\n",	       oldbuflen, newlen );	doc->cdata = realloc( doc->cdata, newlen );	doc->cdata_buflen = newlen;	/* Zero-out the new bit of buffer */	memset( doc->cdata+oldbuflen, 0, newlen-oldbuflen );    }    /* Now simply copy the new cdata onto the end of the buffer */    memcpy( doc->cdata+doc->cdata_len, cdata, len );    doc->cdata_len += len;    DEBUG( DEBUG_XML, "Collected %d bytes of cdata, buffer now:\n%s\n",	   len, doc->cdata );}static void http_get_content_charset( const char *name, const char *value ) {    char **pairs;    int n;    if( strcasecmp( name, "Content-Type" ) == 0 ) {	/* Get the charset so we can pass it on to expat */	pairs = strpairs( value, ';', '=', http_quotes, http_whitespace );	for( n = 0; pairs[n] != NULL; n+=2 ) {	    if( (strcasecmp( pairs[n], "charset") == 0) &&		pairs[n+1] != NULL ) {		DOFREE( http_content_charset );		/* Strip off the quotes */		http_content_charset = strstrip( pairs[n+1], '\"' );		DEBUG( DEBUG_HTTP, "Got content type charset: %s\n",		       http_content_charset );	    }	}	strpairs_free( pairs );    }    return;}static void dav_xml_parsebody( void *userdata, 			const char *buffer, const size_t len ) {    struct dav_xmldoc *doc = userdata;    int ret;    /* duck out if it's broken */    if( !doc->valid ) {	DEBUG( DEBUG_XML, "Not parsing %d bytes!\n", len );	return;    }    if( len == 0 ) {	DEBUG( DEBUG_XML, "Got 0-length buffer, end of response.\n" );	ret = XML_Parse( dav_xml_parser, "", 0, -1 );    } else {	DEBUG( DEBUG_XML, "Got %d length buffer.\n", len );	ret = XML_Parse( dav_xml_parser, buffer, len, 0 );    }    DEBUG( DEBUG_XML, "XML_Parse returned %d\n", ret );    if( ret == 0 ) {	doc->valid = false;    }}/* WebDAV fetch mode handler. */int dav_fetch( const char *dirname, struct proto_file_t **files ) {    http_req_t req;    struct dav_xmldoc doc = {0};    int ret;    const char *propfind_body =	"<?xml version=\"1.0\"?>" EOL /* should we use encoding=? */	"<propfind xmlns=\"DAV:\">" EOL	"  <prop>" EOL	"    <getcontentlength/>" EOL	"    <getlastmodified/>" EOL	"    <resourcetype/>" EOL	"  </prop>" EOL	"</propfind>" EOL;    const char *myheaders =	"Content-Type: text/xml" EOL /* should we use charset=? */	"Depth: infinity" EOL;           dav_xml_parser = XML_ParserCreate( NULL );    XML_SetElementHandler( dav_xml_parser, dav_xml_startelm, dav_xml_endelm );    XML_SetCharacterDataHandler( dav_xml_parser, dav_xml_cdata );    XML_SetUserData( dav_xml_parser, (void *) &doc );    /* Create a dummy state to act as the root element in the      * tree. Just makes things a little bit easier since we can      * then always presume we have a ->parent element.     */    doc.root = malloc( sizeof( struct dav_xml_state ) );    memset( doc.root, 0, sizeof( struct dav_xml_state ) );    doc.root->tag = dav_xml_root;    doc.root->tag_name = "@root@";    /* And set it to the current element */    doc.current = doc.root;    /* Init the document */    doc.files = NULL;    doc.fetch_root = dirname;    doc.valid = true; /* so far... */    doc.file = malloc( sizeof( struct proto_file_t ) );    memset( doc.file, 0, sizeof( struct proto_file_t ) );    http_request_init( &req, "PROPFIND", dirname );    req.body_callback = dav_xml_parsebody;    req.body_callback_userdata = &doc;    req.body = http_body_buffer;    req.body_buffer = propfind_body;    /* Add in the content type header */    strcat( req.headers, myheaders );        ret = http_request( &req );    XML_ParserFree( dav_xml_parser );    free( doc.root );    if( ret == PROTO_OK && req.class == 2 && doc.valid ) {	*files = doc.files;	ret = PROTO_OK;    } else {	*files = NULL;	ret = PROTO_ERROR;    }    http_request_end( &req );    return ret;}#endif /* HAVE_LIBEXPAT */int http_head( const char *directory ) {    http_req_t req;    int ret;        http_request_init( &req, "HEAD", directory );    ret = http_request( &req );    if( ret == PROTO_OK && req.class != 2 )	ret = PROTO_ERROR;        http_request_end( &req );    return ret;}static void http_options_parsehdr( const char *name, const char *value ) {    char **classes, **class;    if( strcasecmp( name, "DAV" ) == 0 ) {	DEBUG( DEBUG_HTTP, "Got OPTIONS header with value: %s\n", value );	classes = strsplit( value, ',', http_quotes, http_whitespace );	for( class = classes; *class!=NULL; class++ ) {	    DEBUG( DEBUG_HTTP, "Got compliance class: [%s]\n", *class );	    if( strncmp( *class, "1", 1 ) == 0 ) {		DEBUG( DEBUG_HTTP, "Class 1 compliant server.\n" );		http_webdav_server = true;	    }	}	strsplit_free( classes );    }}/* Performs an OPTIONS request. * Sets http_webdav_server appropriately. */int http_options( const char *directory ) {    http_req_t req;    int ret;        http_webdav_server = false;    http_request_init( &req, "OPTIONS", directory );    req.hdrs_callback = http_options_parsehdr;    ret = http_request( &req );    if( ret == PROTO_OK && req.class != 2 )	ret = PROTO_ERROR;        http_request_end( &req );    return ret;}

⌨️ 快捷键说明

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