📄 uri.c
字号:
/* GNet - Networking library * Copyright (C) 2000-2003 David Helder, David Bolcsfoldi, Eric Williams * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//* FIXME: #include "gnet-private.h" */#include <glib.h>#include <string.h>#include <malloc.h>#include <ctype.h>#include "uri.h"#include <string.h>static void field_unescape (char *str);static char* field_escape (char* str, unsigned char mask);#define USERINFO_ESCAPE_MASK 0x01#define PATH_ESCAPE_MASK 0x02#define QUERY_ESCAPE_MASK 0x04#define FRAGMENT_ESCAPE_MASK 0x08/* #define FALSE 0 *//* #define TRUE (!FALSE) */static unsigned char neednt_escape_table[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x00, 0x0c, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};/*Perl code to generate above table:#!/usr/bin/perl$ok = "abcdefghijklmnopqrstuvwxyz" . "ABCDEFGHIJKLMNOPQRSTUVWXYZ" . "0123456789" . "-_.!~*'()";$userinfo_ok = ';:&=+\$,';$path_ok = ':\@&=+\$,;/';$query_ok = ';/?:\@&=+\$,';$fragment_ok = ';/?:\@&=+\$,';for ($i = 0; $i < 32; $i++){ print " "; for ($j = 0; $j < 8; $j++) { $num = 0; $letter = chr(($i * 8) + $j); $num |= 0b0001 if (index($userinfo_ok, $letter) != -1); $num |= 0b0010 if (index($path_ok, $letter) != -1); $num |= 0b0100 if (index($query_ok, $letter) != -1); $num |= 0b1000 if (index($fragment_ok, $letter) != -1); $num |= 0b1111 if (index($ok, $letter) != -1); printf "0x%02x, ", $num; } print "\n";}*//* our own ISSPACE. ANSI isspace is local dependent */#define ISSPACE(C) (((C) >= 9 && (C) <= 13) || (C) == ' ')static int split_user_passwd(const char* in, char** user, char** passwd){ char *tmp = strdup(in); if(!tmp) return 0; *passwd = strchr(tmp, ':'); if(!(*passwd)) { free(tmp); return 0; } *((*passwd)++) = '\0'; // don't you love C? :) *user = strdup(tmp); if(!*user) return 0; *passwd = strdup(*passwd); if(!*passwd) return 0; free(tmp); return 1;}/** * gnet_uri_new * @uri: URI string * * Creates a #GURI from a string. Empty fields are set to NULL. The * parser does not validate the URI -- it will accept some malformed * URI. URIs are usually in the form * scheme://userinfo@hostname:port/path?query#fragment * * URIs created from user input are typically unescaped. URIs * created from machine input (e.g. received over the internet) are * typically escaped. * * Returns: a new #GURI, or NULL if there was a failure. * **/GURI* gnet_uri_new (const char* uri){ GURI* guri = NULL; const char* p; const char* temp; g_return_val_if_fail (uri, NULL); /* Skip initial whitespace */ p = uri; while (*p && ISSPACE((int)*p)) ++p; if (!*p) /* Error if it's just a string of space */ return NULL; guri = g_new0 (GURI, 1); /* Scheme */ temp = p; while (*p && *p != ':' && *p != '/' && *p != '?' && *p != '#') ++p; if (*p == ':') { guri->scheme = g_strndup (temp, p - temp); ++p; } else /* This char is NUL, /, ?, or # */ p = temp; /* Authority */ if (*p == '/' && p[1] == '/') { char *userinfo; p += 2; /* Userinfo */ temp = p; while (*p && *p != '@' && *p != '/' ) /* Look for @ or / */ ++p; if (*p == '@') /* Found userinfo */ { userinfo = g_strndup (temp, p - temp); if(!split_user_passwd(userinfo, &guri->user, &guri->passwd)) { free(userinfo); goto error; } free(userinfo); ++p; } else p = temp; /* Hostname */ /* Check for IPv6 canonical hostname in brackets */ if (*p == '[') { p++; /* Skip [ */ temp = p; while (*p && *p != ']') ++p; if ((p - temp) == 0) goto error; guri->hostname = g_strndup (temp, p - temp); if (*p) p++; /* Skip ] (if there) */ } else { temp = p; while (*p && *p != '/' && *p != '?' && *p != '#' && *p != ':') ++p; if ((p - temp) == 0) goto error; guri->hostname = g_strndup (temp, p - temp); } /* Port */ if (*p == ':') { for (++p; isdigit((int)*p); ++p) guri->port = guri->port * 10 + (*p - '0'); } } /* Path (we are liberal and won't check if it starts with /) */ temp = p; while (*p && *p != '?' && *p != '#') ++p; if (p != temp) guri->path = g_strndup(temp, p - temp); /* Query */ if (*p == '?') { temp = p + 1; while (*p && *p != '#') ++p; guri->query = g_strndup (temp, p - temp); } /* Fragment */ if (*p == '#') { ++p; guri->fragment = g_strdup (p); } return guri; error: gnet_uri_delete (guri); return NULL;}/** * gnet_uri_new_fields * @scheme: scheme * @hostname: host name * @port: port * @path: path * * Creates a #GURI from the fields. This function uses the most * common fields. Use gnet_uri_new_fields_all() to specify all * fields. * * Returns: a new #GURI. * **/GURI* gnet_uri_new_fields (const char* scheme, const char* hostname, const gint port, const char* path){ GURI* uri = NULL; uri = g_new0 (GURI, 1); if (scheme) uri->scheme = g_strdup (scheme); if (hostname) uri->hostname = g_strdup (hostname); uri->port = port; if (path) uri->path = g_strdup (path); return uri;}/** * gnet_uri_new_fields_all * @scheme: scheme * @userinfo: user info * @hostname: host name * @port: port * @path: path * @query: query * @fragment: fragment * * Creates a #GURI from all fields. * * Returns: a new #GURI. * **/GURI*gnet_uri_new_fields_all (const char* scheme, const char* user, const char* passwd, const char* hostname, const gint port, const char* path, const char* query, const char* fragment){ GURI* uri = NULL; uri = g_new0 (GURI, 1); if (scheme) uri->scheme = g_strdup (scheme); if (user) uri->user = g_strdup (user); if (passwd) uri->passwd = g_strdup (passwd); if (hostname) uri->hostname = g_strdup (hostname); uri->port = port; if (path) uri->path = g_strdup (path); if (query) uri->query = g_strdup (query); if (fragment) uri->fragment = g_strdup (fragment); return uri;}/** * gnet_uri_clone: * @uri: a #GURI * * Copies a #GURI. * * Returns: a copy of @uri. * **/GURI* gnet_uri_clone (const GURI* uri){ GURI* uri2; g_return_val_if_fail (uri, NULL); uri2 = g_new0 (GURI, 1); uri2->scheme = g_strdup (uri->scheme); uri2->user = g_strdup (uri->user); uri2->passwd = g_strdup (uri->passwd); uri2->hostname = g_strdup (uri->hostname); uri2->port = uri->port; uri2->path = g_strdup (uri->path); uri2->query = g_strdup (uri->query); uri2->fragment = g_strdup (uri->fragment); return uri2;}/** * gnet_uri_delete: * @uri: a #GURI * * Deletes a #GURI. * **/voidgnet_uri_delete (GURI* uri){ if (uri) { g_free (uri->scheme); g_free (uri->user); g_free (uri->passwd); g_free (uri->hostname); g_free (uri->path); g_free (uri->query); g_free (uri->fragment); g_free (uri); }}#define SAFESTRCMP(A,B) (((A)&&(B))?(strcmp((A),(B))):((A)||(B)))/** * gnet_uri_equal * @p1: a #GURI * @p2: another #GURI * * Compares two #GURI's for equality. * * Returns: TRUE if they are equal; FALSE otherwise. * **/intgnet_uri_equal (gconstpointer p1, gconstpointer p2){ const GURI* uri1 = (const GURI*) p1; const GURI* uri2 = (const GURI*) p2; g_return_val_if_fail (uri1, FALSE); g_return_val_if_fail (uri2, FALSE); if (uri1->port == uri2->port && !SAFESTRCMP(uri1->scheme, uri2->scheme) && !SAFESTRCMP(uri1->user, uri2->user) && !SAFESTRCMP(uri1->passwd, uri2->passwd) && !SAFESTRCMP(uri1->hostname, uri2->hostname) && !SAFESTRCMP(uri1->path, uri2->path) && !SAFESTRCMP(uri1->query, uri2->query) && !SAFESTRCMP(uri1->fragment, uri2->fragment)) return TRUE; return FALSE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -