Add new examples
This commit is contained in:
+2
-8
@@ -1,8 +1,2 @@
|
||||
test
|
||||
test.exe
|
||||
reference.out
|
||||
reference.exe
|
||||
parse.out
|
||||
parse.exe
|
||||
decode_field.out
|
||||
decode_field.exe
|
||||
*.out
|
||||
*.exe
|
||||
|
||||
@@ -7,3 +7,4 @@ It features
|
||||
* The ability to switch between RFC 3986 and WHATWG with a flag
|
||||
* Relative reference parsing and resolution
|
||||
* URL normalization
|
||||
* Doesn't rely on null-terminated strings
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
gcc url.c examples/reference.c -o reference.exe -Wall -Wextra -ggdb
|
||||
gcc url.c examples/parse.c -o parse.exe -Wall -Wextra -ggdb
|
||||
gcc url.c examples/decode_field.c -o decode_field.exe -Wall -Wextra -ggdb
|
||||
gcc -o 000_parse.exe examples/000_parse.c url.c -I. -Wall -Wextra -ggdb
|
||||
gcc -o 001_serialize.exe examples/001_serialize.c url.c -I. -Wall -Wextra -ggdb
|
||||
gcc -o 002_partial_parse.exe examples/002_partial_parse.c url.c -I. -Wall -Wextra -ggdb
|
||||
gcc -o 003_references.exe examples/003_references.c url.c -I. -Wall -Wextra -ggdb
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
gcc url.c examples/reference.c -o reference.out -Wall -Wextra -ggdb
|
||||
gcc url.c examples/parse.c -o parse.out -Wall -Wextra -ggdb
|
||||
gcc url.c examples/decode_field.c -o decode_field.out -Wall -Wextra -ggdb
|
||||
gcc -o 000_parse.out examples/000_parse.c url.c -I. -Wall -Wextra -ggdb
|
||||
gcc -o 001_serialize.out examples/001_serialize.c url.c -I. -Wall -Wextra -ggdb
|
||||
gcc -o 002_partial_parse.out examples/002_partial_parse.c url.c -I. -Wall -Wextra -ggdb
|
||||
gcc -o 003_references.out examples/003_references.c url.c -I. -Wall -Wextra -ggdb
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <url.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char url[] = "http://example.com";
|
||||
|
||||
// This is how you parse an URL
|
||||
URL parsed_url;
|
||||
int ret = url_parse(url, strlen(url), NULL, &parsed_url, 0);
|
||||
if (ret < 0) {
|
||||
printf("Invalid URL!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Now the URL's component are stored in the URL
|
||||
// structure. Note that the fields of URL are slices
|
||||
// into the source string.
|
||||
|
||||
// Let's print the URL's domain. Note that any
|
||||
// field except for the scheme may be percent-encoded,
|
||||
// so if you want the raw representation of a
|
||||
// field you should decode it:
|
||||
char domain[1<<9];
|
||||
int domain_len = url_percent_decode(parsed_url.host_text, domain, sizeof(domain));
|
||||
|
||||
// url_percent_decode may fail if the percent-encoding
|
||||
// is invalid or the buffer is too small. The url_parse
|
||||
// function validates the percent-encoding, so we only
|
||||
// need to worry about the buffer size.
|
||||
assert(domain_len > -1);
|
||||
if (domain_len >= (int) sizeof(domain)) {
|
||||
printf("Domain buffer is too small\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Note that url.c never adds null characters to outputs
|
||||
domain[domain_len] = '\0';
|
||||
|
||||
printf("The domain is: %s\n", domain);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <url.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// We can translate parsed URLs back into strings
|
||||
// using the url_serialize function
|
||||
|
||||
char url[] = "http://example.com";
|
||||
|
||||
URL parsed_url;
|
||||
int ret = url_parse(url, strlen(url), NULL, &parsed_url, 0);
|
||||
if (ret < 0) {
|
||||
printf("Invalid URL!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buf[1<<9];
|
||||
ret = url_serialize(&parsed_url, NULL, buf, sizeof(buf));
|
||||
|
||||
// On error, url_serialize returns -1. Errors can
|
||||
// only occur when relative references are involved,
|
||||
// which isn't our case.
|
||||
assert(ret > -1);
|
||||
|
||||
// We still need to worry about the buffer's capacity
|
||||
// though.
|
||||
if (ret >= (int) sizeof(buf)) {
|
||||
printf("Serialization buffer is too small\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// url.c never adds null terminators
|
||||
buf[ret] = '\0';
|
||||
|
||||
printf("Serialized URL: %s\n", buf);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#include <url.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// We can also parse URLs when they are part of a larger
|
||||
// string. This is useful when we know the starting offset
|
||||
// of an URL but don't know the end.
|
||||
//
|
||||
// For instance, say we have this string:
|
||||
char str[] = " http://websiteA.com http://websiteB.com/index.html ";
|
||||
int len = sizeof(str)-1;
|
||||
|
||||
// The "pcur" argument of url_parse allows it to tell us
|
||||
// how long the URL is.
|
||||
|
||||
int cur = 0;
|
||||
for (;;) {
|
||||
|
||||
// Skip whitespace preceding the URL
|
||||
while (cur < len && str[cur] == ' ')
|
||||
cur++;
|
||||
|
||||
if (cur == len)
|
||||
break; // No more string
|
||||
|
||||
int url_off = cur;
|
||||
|
||||
URL url;
|
||||
int ret = url_parse(str, len, &cur, &url, 0);
|
||||
if (ret < 0) {
|
||||
printf("Invalid URL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int url_len = cur - url_off;
|
||||
|
||||
// Thanks to the pcur argument of url_parse we can infer
|
||||
// when the URL ends. We can get the original text of the
|
||||
// URL my slicing the source string using the starting and
|
||||
// end offsets, or use something like url_serialize to
|
||||
// translate the URL structure into a string.
|
||||
printf("Found an URL: %.*s\n", url_len, str + url_off);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#include <url.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// url.c also allows us to parse relative references to URLs.
|
||||
// These are strings that aren't technically URLs but may be
|
||||
// evaluated to one in reference to a base URL.
|
||||
//
|
||||
// Here's an example:
|
||||
char base_url[] = "http://example.com/files/document.txt";
|
||||
char relative_reference[] = "../images/cat.png";
|
||||
|
||||
// The url_serialize function allows us to translate the
|
||||
// reference into an URL. But first, we need to parse both
|
||||
// the base URL and reference.
|
||||
|
||||
URL parsed_base_url;
|
||||
int ret = url_parse(base_url, strlen(base_url), NULL, &parsed_base_url, 0);
|
||||
if (ret < 0) {
|
||||
printf("Invalid base URL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Note that url_parse will reject relative references by
|
||||
// default. We need to pass the URL_FLAG_ALLOWREF flag.
|
||||
URL parsed_relative_reference;
|
||||
ret = url_parse(relative_reference, strlen(relative_reference),
|
||||
NULL, &parsed_relative_reference, URL_FLAG_ALLOWREF);
|
||||
if (ret < 0) {
|
||||
printf("Invalid relative reference\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Now we can resolve the reference by serializing it with
|
||||
// the base URL
|
||||
char buf[1<<9];
|
||||
ret = url_serialize(&parsed_relative_reference, &parsed_base_url, buf, sizeof(buf));
|
||||
|
||||
// Since url_serialize was called with a non-NULL base URL
|
||||
// argument, it may fail. We need to check for a negative
|
||||
// return value.
|
||||
if (ret < 0) {
|
||||
printf("Reference resolution failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that the buffer's capacity was enough
|
||||
if (ret >= (int) sizeof(buf)) {
|
||||
printf("Serialization buffer is too small\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// All good. Now we can print the result
|
||||
buf[ret] = '\0';
|
||||
printf("Resolved reference: %s\n", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../url.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char src[] = "http://web%73ite.com";
|
||||
|
||||
URL parsed;
|
||||
int ret = url_parse(src, strlen(src), NULL, 1, &parsed);
|
||||
if (ret < 0) {
|
||||
printf("Couldn't parse base URL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("%.*s\n",
|
||||
parsed.host_text.len,
|
||||
parsed.host_text.ptr);
|
||||
|
||||
char buf[100];
|
||||
ret = url_decode_field(parsed.host_text, buf, (int) sizeof(buf)-1);
|
||||
if (ret < 0 || ret >= (int) sizeof(buf)) {
|
||||
printf("Couldn't decode field\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("%.*s\n", ret, buf);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../url.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char src[] = "http://website.com/users/000?filter=no#title";
|
||||
|
||||
URL parsed;
|
||||
int ret = url_parse(src, strlen(src), NULL, 1, &parsed);
|
||||
if (ret < 0) {
|
||||
printf("Couldn't parse base URL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// http
|
||||
printf("scheme=%.*s\n",
|
||||
parsed.scheme.len,
|
||||
parsed.scheme.ptr);
|
||||
|
||||
// (empty)
|
||||
if (parsed.username.len == 0)
|
||||
printf("username=(empty)\n");
|
||||
else
|
||||
printf("username=%.*s\n",
|
||||
parsed.username.len,
|
||||
parsed.username.ptr);
|
||||
|
||||
// (password)
|
||||
if (parsed.password.len == 0)
|
||||
printf("password=(empty)\n");
|
||||
else
|
||||
printf("password=%.*s\n",
|
||||
parsed.password.len,
|
||||
parsed.password.ptr);
|
||||
|
||||
if (parsed.host_type == URL_HOST_EMPTY)
|
||||
printf("host=(empty)\n");
|
||||
else
|
||||
printf("host=%.*s\n",
|
||||
parsed.host_text.len,
|
||||
parsed.host_text.ptr);
|
||||
|
||||
if (parsed.no_port)
|
||||
printf("port=(empty)\n");
|
||||
else
|
||||
printf("port=%d\n", parsed.port);
|
||||
|
||||
printf("path=%.*s\n",
|
||||
parsed.path.len,
|
||||
parsed.path.ptr);
|
||||
|
||||
printf("query=%.*s\n",
|
||||
parsed.query.len,
|
||||
parsed.query.ptr);
|
||||
|
||||
printf("fragment=%.*s\n",
|
||||
parsed.fragment.len,
|
||||
parsed.fragment.ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../url.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char base[] = "http://website.com/users/000";
|
||||
char ref[] = "../images/cat.png";
|
||||
|
||||
URL parsed_base;
|
||||
int ret = url_parse(base, strlen(base), NULL, 1, &parsed_base);
|
||||
if (ret < 0) {
|
||||
printf("Couldn't parse base URL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char dst[1<<10];
|
||||
ret = url_resolve_reference(ref, strlen(ref), NULL, &parsed_base, 1, dst, (int) sizeof(dst));
|
||||
if (ret < 0) {
|
||||
printf("Couldn't resolve reference\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// http://website.com/images/cat.png
|
||||
printf("%.*s\n", ret, dst);
|
||||
return 0;
|
||||
}
|
||||
+2
-2
@@ -3,11 +3,11 @@
|
||||
ifeq ($(shell uname -s),Windows_NT)
|
||||
EXT = .exe
|
||||
else
|
||||
EXT =
|
||||
EXT = .out
|
||||
endif
|
||||
|
||||
all:
|
||||
gcc -o test$(EXT) test.c ../url.c cJSON.c -Wall -Wextra -ggdb
|
||||
|
||||
clean:
|
||||
rm test test.exe
|
||||
rm test.out test.exe
|
||||
|
||||
Binary file not shown.
@@ -1,4 +1,3 @@
|
||||
#include <string.h>
|
||||
#include "url.h"
|
||||
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
@@ -35,10 +34,21 @@
|
||||
#define UINT8_MAX (URL_u8) ((1 << 8)-1)
|
||||
#define UINT16_MAX (URL_u16) ((1 << 16)-1)
|
||||
|
||||
#define NULL ((void*) 0)
|
||||
#define S(X) ((URL_String) { (X), sizeof(X)-1 })
|
||||
#define EMPTY (URL_String) { (void*) 0, 0 }
|
||||
#define EMPTY (URL_String) { NULL, 0 }
|
||||
#define SLICE(src, off, end) (URL_String) { src + off, end - off }
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define memcpy_ __builtin_memcpy
|
||||
#else
|
||||
static void memcpy_(char *dst, char *src, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
#endif
|
||||
|
||||
static URL_b32 streq(URL_String a, URL_String b)
|
||||
{
|
||||
if (a.len != b.len)
|
||||
@@ -734,7 +744,7 @@ static void append(Builder *b, URL_String s)
|
||||
int copy = s.len;
|
||||
if (copy > unused)
|
||||
copy = unused;
|
||||
memcpy(b->dst + b->len, s.ptr, copy);
|
||||
memcpy_(b->dst + b->len, s.ptr, copy);
|
||||
}
|
||||
b->len += s.len;
|
||||
}
|
||||
@@ -806,7 +816,7 @@ int url_serialize(URL *url, URL *base, char *dst, int cap)
|
||||
Builder b = { dst, cap, 0 };
|
||||
if (url->scheme.len > 0) {
|
||||
append_scheme(&b, url->scheme);
|
||||
append_authority(&b, url);
|
||||
append_authority(&b, *url);
|
||||
append(&b, url->path);
|
||||
append_query(&b, url->query);
|
||||
} else {
|
||||
@@ -818,7 +828,7 @@ int url_serialize(URL *url, URL *base, char *dst, int cap)
|
||||
ASSERT(base->scheme.len > 0);
|
||||
append_scheme(&b, base->scheme);
|
||||
if (!url->no_authority) {
|
||||
append_authority(&b, url);
|
||||
append_authority(&b, *url);
|
||||
PathComps comps = {0};
|
||||
if (resolve_dots_and_append_comps(&comps, url->path) < 0)
|
||||
return -1;
|
||||
|
||||
@@ -25,23 +25,19 @@
|
||||
//
|
||||
// For more information, please refer to <https://unlicense.org>
|
||||
|
||||
#define URL_STATIC_ASSERT _Static_assert
|
||||
|
||||
typedef unsigned char URL_u8;
|
||||
typedef unsigned short URL_u16;
|
||||
typedef unsigned int URL_u32;
|
||||
typedef unsigned int URL_b32;
|
||||
|
||||
URL_STATIC_ASSERT(sizeof(URL_u8) == 1, "");
|
||||
URL_STATIC_ASSERT(sizeof(URL_u16) == 2, "");
|
||||
URL_STATIC_ASSERT(sizeof(URL_u32) == 4, "");
|
||||
URL_STATIC_ASSERT(sizeof(URL_b32) == 4, "");
|
||||
|
||||
typedef struct {
|
||||
char *ptr;
|
||||
int len;
|
||||
} URL_String;
|
||||
|
||||
typedef struct { URL_u32 data; } URL_IPv4;
|
||||
typedef struct { URL_u16 data[8]; } URL_IPv6;
|
||||
|
||||
typedef enum {
|
||||
URL_HOST_EMPTY,
|
||||
URL_HOST_IPV4,
|
||||
@@ -49,17 +45,6 @@ typedef enum {
|
||||
URL_HOST_NAME,
|
||||
} URL_HostType;
|
||||
|
||||
typedef struct {
|
||||
URL_u32 data;
|
||||
} URL_IPv4;
|
||||
|
||||
typedef struct {
|
||||
URL_u16 data[8];
|
||||
} URL_IPv6;
|
||||
|
||||
URL_STATIC_ASSERT(sizeof(URL_IPv4) == 4, "");
|
||||
URL_STATIC_ASSERT(sizeof(URL_IPv6) == 16, "");
|
||||
|
||||
typedef struct {
|
||||
|
||||
// These flags are used to differentiate between
|
||||
@@ -79,6 +64,7 @@ typedef struct {
|
||||
URL_String scheme;
|
||||
|
||||
// Both may be empty
|
||||
// May be percent-encoded
|
||||
URL_String username;
|
||||
URL_String password;
|
||||
|
||||
@@ -88,6 +74,7 @@ typedef struct {
|
||||
// (host byte order).
|
||||
// Note that the host may be empty, in which
|
||||
// case host_type=URL_HOST_EMPTY.
|
||||
// If host_text is set, it may be percent-encoded.
|
||||
URL_HostType host_type;
|
||||
URL_String host_text;
|
||||
union {
|
||||
@@ -100,12 +87,15 @@ typedef struct {
|
||||
URL_b32 no_port;
|
||||
URL_u16 port;
|
||||
|
||||
// May be percent-encoded
|
||||
URL_String path;
|
||||
|
||||
// May be empty
|
||||
// May be percent-encoded
|
||||
URL_String query;
|
||||
|
||||
// May be empty
|
||||
// May be percent-encoded
|
||||
URL_String fragment;
|
||||
|
||||
} URL;
|
||||
|
||||
Reference in New Issue
Block a user