On Tuesday 01 August 2006 10:07, david reid wrote:
> Having looked at these, they're small and self contained and would seem
> to be a good fit for apr-util. Question is where/how would they go in?
+1 in principle, and I agree apr_uri is not a great match.
Maybe it would fit as a new apr_uriencode source file in the /uri/ directory?
> Once we have an answer I'll submit a patch :-)
Which reminds me, support for *relative* URLs still isn't in apr_uri,
and I've been shipping it separately for years in apps that need it.
Anyone object to the attached patch going in?
--
Nick Kew
Index: uri/apr_uri.c
===================================================================
--- uri/apr_uri.c (revision 427512)
+++ uri/apr_uri.c (working copy)
@@ -460,3 +460,93 @@
}
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);
+}
Index: include/apr_uri.h
===================================================================
--- include/apr_uri.h (revision 427512)
+++ include/apr_uri.h (working copy)
@@ -160,6 +160,37 @@
apr_uri_t *uptr);
/**
+ * Resolve a (possibly-relative) URI against a given base URI.
+ * Fill in all supplied fields of a apr_uri_t structure.
+ * This eliminates the necessity of extracting host, port,
+ * path, query info repeatedly in the modules.
+ * @param p The pool to allocate out of
+ * @param base The base URI to parse against
+ * @param uptr The apr_uri_t to fill out any unset fields of
+ * @return APR_SUCCESS for success or error code
+ */
+APU_DECLARE(apr_status_t) apr_uri_resolve_relative(apr_pool_t *p,
+ const apr_uri_t *base,
+ apr_uri_t *uptr);
+
+/**
+ * Parse a given URI relative to a given base URI.
+ * Fill in all supplied fields of a apr_uri_t structure.
+ * This eliminates the necessity of extracting host, port,
+ * path, query info repeatedly in the modules.
+ * @param p The pool to allocate out of
+ * @param base The base URI to parse against
+ * @param uri The uri to parse
+ * @param uptr The apr_uri_t to fill out
+ * @return APR_SUCCESS for success or error code
+ */
+APU_DECLARE(apr_status_t) 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