Commit 30a16b53 authored by Geoff Simmons's avatar Geoff Simmons

first version with URL encoding

parent 7b8a1650
......@@ -12,6 +12,7 @@ libvmod_blobcode_la_SOURCES = \
base64.h \
base64.c \
hex.c \
url.c \
wb.h \
wb.c
......
......@@ -116,7 +116,10 @@ my @vals = (qw(
BASE64URLNOPAD
HEX
HEXUC
HEXLC));
HEXLC
URL
URLLC
URLUC));
unless ($#ARGV == 1) {
printf(STDERR 'Usage: '.$0." <c-file> <h-file>\n");
......
This diff is collapsed.
/*-
* Copyright 2015-2016 UPLEX - Nils Goroll Systemoptimierung
* All rights reserved.
*
* Authors: Nils Goroll <nils.goroll@uplex.de>
* Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <errno.h>
#include <stdint.h>
#include "vmod_blobcode.h"
#include "vrt.h"
#include "vas.h"
enum state_e {
NORMAL,
PERCENT,
FIRSTNIB,
};
size_t
url_encode_l(size_t l)
{
return l * 3;
}
size_t
url_decode_l(size_t l)
{
return l;
}
/*
* Bitmap of unreserved characters according to RFC 3986 section 2.3
* (locale-independent and cacheline friendly)
*/
static const uint8_t unreserved[] = {
0x0, 0x0, 0x0, 0x0, 0x0, 0x60, 0xff, 0x3,
0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x47,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
static const char hex_alphabet[][16] = {
"0123456789abcdef",
"0123456789ABCDEF"
};
/*
* Shift the ASCII table over so that it begins at '0', and replace the
* hex digits with their binary values. This fits all of the hex digits
* into 55 bytes (cacheline friendly).
*/
static const uint8_t nibble[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 10, 11, 12,
13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 10,
11, 12, 13, 14, 15
};
static inline char
hex2byte(const unsigned char hi, const unsigned char lo)
{
return (nibble[hi - '0'] << 4) | nibble[lo - '0'];
}
static inline int
isunreserved(const uint8_t c)
{
return (unreserved[c >> 3] & (1 << (c & 7)));
}
ssize_t
url_encode(const enum encoding enc, char *restrict const buf,
const size_t buflen, const char *restrict const in,
const size_t inlen)
{
char *p = buf;
const char *alphabet = hex_alphabet[0];
AN(buf);
assert(enc == URLUC || enc == URLLC);
if (in == NULL || inlen == 0)
return 0;
if (enc != URLLC)
alphabet = hex_alphabet[1];
for (int i = 0; i < inlen; i++) {
if (isunreserved(in[i])) {
if (p + 1 - buf > buflen)
return -1;
*p++ = in[i];
}
else {
if (p + 3 - buf > buflen)
return -1;
*p++ = '%';
*p++ = alphabet[(in[i] & 0xf0) >> 4];
*p++ = alphabet[in[i] & 0x0f];
}
}
return p - buf;
}
ssize_t
url_decode(const enum encoding dec, char *restrict const buf,
const size_t buflen, ssize_t n, const char *restrict const p,
va_list ap)
{
char *dest = buf;
const char * const end = buf + buflen;
size_t len = SIZE_MAX;
uint8_t nib = 0;
enum state_e state = NORMAL;
AN(buf);
assert(dec == URL);
if (n >= 0 && n < len)
len = n;
for (const char *s = p; len > 0 && s != vrt_magic_string_end;
s = va_arg(ap, const char *)) {
if (s == NULL || *s == '\0')
continue;
while (*s && len) {
uint8_t nib2;
if (dest + 1 > end) {
errno = ENOMEM;
return -1;
}
switch(state) {
case NORMAL:
if (*s == '%')
state = PERCENT;
else
*dest++ = *s;
break;
case PERCENT:
if ((nib = nibble[*s - '0']) == 0xff) {
errno = EINVAL;
return -1;
}
state = FIRSTNIB;
break;
case FIRSTNIB:
if ((nib2 = nibble[*s - '0']) == 0xff) {
errno = EINVAL;
return -1;
}
*dest++ = (nib << 4) | nib2;
nib = 0;
state = NORMAL;
break;
default:
WRONG("illegal URL decode state");
}
s++;
len--;
}
}
if (state != NORMAL) {
errno = EINVAL;
return -1;
}
assert(dest <= end);
return dest - buf;
}
......@@ -57,6 +57,12 @@ struct vmod_blobcode_blob {
.encode_l = hex_encode_l, \
.encode = hex_encode
#define URL_FUNCS \
.decode_l = url_decode_l, \
.decode = url_decode, \
.encode_l = url_encode_l, \
.encode = url_encode
static const struct vmod_blobcode_fptr {
len_f *const decode_l;
decode_f *const decode;
......@@ -96,11 +102,21 @@ static const struct vmod_blobcode_fptr {
},
[HEXLC] = {
HEX_FUNCS
},
[URL] = {
URL_FUNCS
},
[URLUC] = {
URL_FUNCS
},
[URLLC] = {
URL_FUNCS
}
};
#undef B64_FUNCS
#undef HEX_FUNCS
#undef URL_FUNCS
#define ERR(ctx, msg) \
errmsg((ctx), "vmod blobcode error: " msg)
......
......@@ -112,9 +112,16 @@ len_f base64_encode_l;
encode_f base64_encode;
decode_f base64_decode;
/* hex.c */
/* hex.c */
len_f hex_encode_l;
len_f hex_decode_l;
encode_f hex_encode;
decode_f hex_decode;
/* url.c */
len_f url_encode_l;
len_f url_decode_l;
encode_f url_encode;
decode_f url_decode;
......@@ -135,7 +135,7 @@ byte. For example::
req.http.First + req.http.Second));
$Function BLOB decode(ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD,
HEX} decoding, STRING_LIST encoded)
HEX, URL} decoding, STRING_LIST encoded)
Description
Returns the BLOB derived from the string ``encoded``
......@@ -146,7 +146,7 @@ Example
$Function BLOB decode_n(INT n,
ENUM {IDENTITY, BASE64, BASE64URL,
BASE64URLNOPAD, HEX} decoding,
BASE64URLNOPAD, HEX, URL} decoding,
STRING_LIST encoded)
Description
......@@ -155,7 +155,7 @@ Description
the string, then return the same result as ``decode()``.
$Function STRING encode(ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD,
HEXUC, HEXLC} encoding, BLOB blob)
HEXUC, HEXLC, URLUC, URLLC} encoding, BLOB blob)
Description
Returns a string representation of the BLOB ``blob`` as
......@@ -166,9 +166,9 @@ Example
``blob=blobcode.decode(BASE64, "Zm9vYmFyYmF6");``
$Function STRING transcode(ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD,
HEX} decoding,
HEX, URL} decoding,
ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD,
HEXUC, HEXLC} encoding,
HEXUC, HEXLC, URLUC, URLLC} encoding,
STRING_LIST encoded)
Description
......@@ -183,9 +183,9 @@ Example
$Function STRING transcode_n(INT n,
ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD,
HEX} decoding,
HEX, URL} decoding,
ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD,
HEXUC, HEXLC} encoding,
HEXUC, HEXLC, URLUC, URLLC} encoding,
STRING_LIST encoded)
Description
......@@ -200,7 +200,8 @@ Description
Example
``std.log("Using VMOD blobcode version " + blobcode.version());``
$Object blob(ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD, HEX} decoding,
$Object blob(ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD, HEX,
URL} decoding,
STRING_LIST encoded)
Prototype
......@@ -223,7 +224,7 @@ Example
``= blobcode.encode(IDENTITY, theblob.get());``
$Method STRING .encode(ENUM {IDENTITY, BASE64, BASE64URL, BASE64URLNOPAD, HEXUC,
HEXLC} encoding)
HEXLC, URLUC, URLLC} encoding)
Description
Returns an encoding of BLOB created by the constructor,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment