+/**
+ * Parse incoming URL for tag and target
+ *
+ * @param plugin plugin
+ * @param url incoming url
+ * @param target where to store the target
+ * @param tag where to store the tag
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error
+ */
+
+static int
+server_parse_url (struct HTTP_Server_Plugin *plugin, const char * url, struct GNUNET_PeerIdentity * target, uint32_t *tag)
+{
+ int debug = GNUNET_YES;
+
+ char * tag_start = NULL;
+ char * tag_end = NULL;
+ char * target_start = NULL;
+ char * separator = NULL;
+ char hash[plugin->peer_id_length+1];
+ int hash_length;
+ unsigned long int ctag;
+
+ /* URL parsing
+ * URL is valid if it is in the form [prefix with (multiple) '/'][peerid[103];tag]*/
+
+ if (NULL == url)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ /* convert tag */
+
+ /* find separator */
+ separator = strrchr (url, ';');
+
+ if (NULL == separator)
+ {
+ if (debug) GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ tag_start = separator + 1;
+
+ if (strlen (tag_start) == 0)
+ {
+ /* No tag after separator */
+ if (debug) GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ ctag = strtoul (tag_start, &tag_end, 10);
+ if (ctag == 0)
+ {
+ /* tag == 0 , invalid */
+ if (debug) GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if ((ctag == ULONG_MAX) && (ERANGE == errno))
+ {
+ /* out of range: > ULONG_MAX */
+ if (debug) GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (ctag > UINT32_MAX)
+ {
+ /* out of range: > UINT32_MAX */
+ if (debug) GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ (*tag) = (uint32_t) ctag;
+ if (NULL == tag_end)
+ {
+ /* no char after tag */
+ if (debug) GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (url[strlen(url)] != tag_end[0])
+ {
+ /* there are more not converted chars after tag */
+ if (debug) GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (debug)
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Found tag `%u' in url\n", (*tag));
+
+ /* convert peer id */
+ target_start = strrchr (url, '/');
+ if (NULL == target_start)
+ {
+ /* no leading '/' */
+ target_start = (char *) url;
+ }
+ target_start++;
+ hash_length = separator - target_start;
+ if (hash_length != plugin->peer_id_length)
+ {
+ /* no char after tag */
+ if (debug) GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ memcpy (hash, target_start, hash_length);
+ hash[hash_length] = '\0';
+
+ if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((const char *) hash, &(target->hashPubKey)))
+ {
+ /* hash conversion failed */
+ if (debug) GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Found target `%s' in url\n", GNUNET_h2s_full(&target->hashPubKey));
+ return GNUNET_OK;
+}
+