[ first submitted in November; folks @apachecon suggested resubmitting ]
--
Nick Kew
--- srclib/apr-util/uri/apr_uri.c 2003-03-03 18:31:58.000000000 +0000
+++ srclib/apr-util/uri/apr_uri.c.new 2003-11-01 14:58:31.000000000 +0000
@@ -448,3 +448,94 @@
}
return APR_EGENERAL;
}
+/* Resolve relative to a base. This means host/etc, and (crucially) path */
+APU_DECLARE(int) apr_uri_resolve_relative(apr_pool_t* pool,
+ const apr_uri_t* base,
+ apr_uri_t* uptr)
+{
+ if ( uptr == NULL
+ || base == NULL
+ || ! base->is_initialized
+ || ! uptr->is_initialized ) {
+ return APR_EGENERAL;
+ }
+/* The interesting bit is the path. */
+ if ( uptr->path == NULL ) {
+ if ( uptr->hostname == NULL ) {
+ /* is this compatible with is_initialised? Harmless in any case */
+ uptr->path = base->path ? base->path : apr_pstrdup(pool, "/") ;
+ }
+ else {
+ /* deal with the idiosyncracy of APR allowing path==NULL
+ ** without risk of breaking back-compatibility
+ */
+ uptr->path = apr_pstrdup(pool, "/") ;
+ }
+ }
+ else if ( uptr->path[0] != '/' ) {
+ size_t baselen ;
+ const char* basepath = base->path ? base->path :"/" ;
+ const char* path = uptr->path ;
+ const char* base_end = strrchr(basepath, '/') ;
+
+ /* if base is nonsensical, bail out */
+ if ( basepath[0] != '/' ) {
+ return APR_EGENERAL;
+ }
+ /* munch "up" components at the start, and chop them from base path */
+ while ( !strncmp(path, "../", 3) ) {
+ while ( base_end > basepath ) {
+ if ( *--base_end == '/' ) {
+ break ;
+ }
+ }
+ path += 3 ;
+ }
+ /* munch "here" components at the start */
+ while ( !strncmp(path, "./", 2) ) {
+ path += 2 ;
+ }
+ baselen = base_end-basepath+1 ;
+ uptr->path = apr_palloc(pool, baselen + strlen(path) + 1 ) ;
+ memcpy(uptr->path, basepath, baselen) ;
+ strcpy(uptr->path+baselen, path) ;
+ }
+
+/* The trivial bits are everything-but-path */
+ if ( uptr->scheme == NULL ) {
+ uptr->scheme = base->scheme ;
+ }
+ if ( uptr->hostinfo == NULL ) {
+ uptr->hostinfo = base->hostinfo ;
+ }
+ if ( uptr->user == NULL ) {
+ uptr->user = base->user ;
+ }
+ if ( uptr->password == NULL ) {
+ uptr->password = base->password ;
+ }
+ if ( uptr->hostname == NULL ) {
+ uptr->hostname = base->hostname ;
+ }
+ if ( uptr->port_str == NULL ) {
+ uptr->port_str = base->port_str ;
+ }
+ if ( uptr->hostent == NULL ) {
+ uptr->hostent = base->hostent ;
+ }
+ if ( ! uptr->port ) {
+ uptr->port = base->port ;
+ }
+ return APR_SUCCESS ;
+}
+APU_DECLARE(int) apr_uri_parse_relative(apr_pool_t* p,
+ const apr_uri_t* base,
+ const char* uri,
+ apr_uri_t* uptr)
+{
+ int ret = apr_uri_parse(p, uri, uptr) ;
+ if ( ret != APR_SUCCESS ) {
+ return ret ;
+ }
+ return apr_uri_resolve_relative(p, base, uptr) ;
+}
--- srclib/apr-util/include/apr_uri.h 2003-03-03 23:41:11.000000000 +0000
+++ srclib/apr-util/include/apr_uri.h.new 2003-11-01 15:00:12.000000000
+0000
@@ -205,6 +205,33 @@
apr_uri_t *uptr);
/**
+ * Resolve an already-initialised but possibly-relative URL
+ * against a given base URL.
+ * @param p The pool to allocate out of
+ * @param base The base to resolve against
+ * @param uptr The apr_uri_t to resolve
+ * @return An HTTP status code
+ */
+APU_DECLARE(int) apr_uri_resolve_relative(apr_pool_t *p,
+ const apr_uri_t *base,
+ apr_uri_t *uptr);
+
+/**
+ * Parse a given URI, fill in all supplied fields of a apr_uri_t structure.
+ * If the given URI is relative, then resolve it using a supplied base
+ * @param p The pool to allocate out of
+ * @param base The base to resolve against
+ * @param uri The uri to parse
+ * @param uptr The apr_uri_t to fill out
+ * @return An HTTP status code
+ */
+APU_DECLARE(int) apr_uri_parse_relative(apr_pool_t *p,
+ const apr_uri_t *base,
+ const char* uri,
+ apr_uri_t* uptr);
+
+
+/**
* Special case for CONNECT parsing: it comes with the hostinfo part only
* @param p The pool to allocate out of
* @param hostinfo The hostinfo string to parse