iodine 0.1.21 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +3 -2
- data/.travis.yml +23 -2
- data/CHANGELOG.md +9 -2
- data/README.md +232 -179
- data/Rakefile +13 -1
- data/bin/config.ru +63 -0
- data/bin/console +6 -0
- data/bin/echo +42 -32
- data/bin/http-hello +62 -0
- data/bin/http-playground +124 -0
- data/bin/playground +62 -0
- data/bin/poc/Gemfile.lock +23 -0
- data/bin/poc/README.md +37 -0
- data/bin/poc/config.ru +66 -0
- data/bin/poc/gemfile +1 -0
- data/bin/poc/www/index.html +57 -0
- data/bin/raw-rbhttp +35 -0
- data/bin/raw_broadcast +66 -0
- data/bin/test_with_faye +40 -0
- data/bin/ws-broadcast +108 -0
- data/bin/ws-echo +108 -0
- data/exe/iodine +59 -0
- data/ext/iodine/base64.c +264 -0
- data/ext/iodine/base64.h +72 -0
- data/ext/iodine/bscrypt-common.h +109 -0
- data/ext/iodine/bscrypt.h +49 -0
- data/ext/iodine/extconf.rb +41 -0
- data/ext/iodine/hex.c +123 -0
- data/ext/iodine/hex.h +70 -0
- data/ext/iodine/http.c +200 -0
- data/ext/iodine/http.h +128 -0
- data/ext/iodine/http1.c +402 -0
- data/ext/iodine/http1.h +56 -0
- data/ext/iodine/http1_simple_parser.c +473 -0
- data/ext/iodine/http1_simple_parser.h +59 -0
- data/ext/iodine/http_request.h +128 -0
- data/ext/iodine/http_response.c +1606 -0
- data/ext/iodine/http_response.h +393 -0
- data/ext/iodine/http_response_http1.h +374 -0
- data/ext/iodine/iodine_core.c +641 -0
- data/ext/iodine/iodine_core.h +70 -0
- data/ext/iodine/iodine_http.c +615 -0
- data/ext/iodine/iodine_http.h +19 -0
- data/ext/iodine/iodine_websocket.c +430 -0
- data/ext/iodine/iodine_websocket.h +21 -0
- data/ext/iodine/libasync.c +552 -0
- data/ext/iodine/libasync.h +117 -0
- data/ext/iodine/libreact.c +347 -0
- data/ext/iodine/libreact.h +244 -0
- data/ext/iodine/libserver.c +912 -0
- data/ext/iodine/libserver.h +435 -0
- data/ext/iodine/libsock.c +950 -0
- data/ext/iodine/libsock.h +478 -0
- data/ext/iodine/misc.c +181 -0
- data/ext/iodine/misc.h +76 -0
- data/ext/iodine/random.c +193 -0
- data/ext/iodine/random.h +48 -0
- data/ext/iodine/rb-call.c +127 -0
- data/ext/iodine/rb-call.h +60 -0
- data/ext/iodine/rb-libasync.h +79 -0
- data/ext/iodine/rb-rack-io.c +389 -0
- data/ext/iodine/rb-rack-io.h +17 -0
- data/ext/iodine/rb-registry.c +213 -0
- data/ext/iodine/rb-registry.h +33 -0
- data/ext/iodine/sha1.c +359 -0
- data/ext/iodine/sha1.h +85 -0
- data/ext/iodine/sha2.c +825 -0
- data/ext/iodine/sha2.h +138 -0
- data/ext/iodine/siphash.c +136 -0
- data/ext/iodine/siphash.h +15 -0
- data/ext/iodine/spnlock.h +235 -0
- data/ext/iodine/websockets.c +696 -0
- data/ext/iodine/websockets.h +120 -0
- data/ext/iodine/xor-crypt.c +189 -0
- data/ext/iodine/xor-crypt.h +107 -0
- data/iodine.gemspec +25 -18
- data/lib/iodine.rb +57 -58
- data/lib/iodine/http.rb +0 -189
- data/lib/iodine/protocol.rb +36 -245
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +145 -2
- metadata +115 -37
- data/bin/core_http_test +0 -51
- data/bin/em playground +0 -56
- data/bin/hello_world +0 -75
- data/bin/setup +0 -7
- data/lib/iodine/client.rb +0 -5
- data/lib/iodine/core.rb +0 -102
- data/lib/iodine/core_init.rb +0 -143
- data/lib/iodine/http/hpack.rb +0 -553
- data/lib/iodine/http/http1.rb +0 -251
- data/lib/iodine/http/http2.rb +0 -507
- data/lib/iodine/http/rack_support.rb +0 -108
- data/lib/iodine/http/request.rb +0 -462
- data/lib/iodine/http/response.rb +0 -474
- data/lib/iodine/http/session.rb +0 -143
- data/lib/iodine/http/websocket_client.rb +0 -335
- data/lib/iodine/http/websocket_handler.rb +0 -101
- data/lib/iodine/http/websockets.rb +0 -336
- data/lib/iodine/io.rb +0 -56
- data/lib/iodine/logging.rb +0 -46
- data/lib/iodine/settings.rb +0 -158
- data/lib/iodine/ssl_connector.rb +0 -48
- data/lib/iodine/timers.rb +0 -95
@@ -0,0 +1,49 @@
|
|
1
|
+
/*
|
2
|
+
(un)copyright: Boaz segev, 2016
|
3
|
+
License: Public Domain except for any non-public-domain algorithms, which are
|
4
|
+
subject to their own licenses.
|
5
|
+
|
6
|
+
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
|
+
*/
|
8
|
+
#ifndef BSCRYPT
|
9
|
+
/**
|
10
|
+
The bscrypt library supplies some **basic** cryptographic functions.
|
11
|
+
|
12
|
+
Read the README file for more details.
|
13
|
+
|
14
|
+
All functions will be available using the prefix `bscrypt_`, i.e.:
|
15
|
+
|
16
|
+
char buffer[13] = {0};
|
17
|
+
bscrypt_base64_encode(buffer, "My String", 9);
|
18
|
+
|
19
|
+
|
20
|
+
*/
|
21
|
+
#define BSCRYPT "0.0.1"
|
22
|
+
|
23
|
+
#include "bscrypt-common.h"
|
24
|
+
#include "base64.h"
|
25
|
+
#include "hex.h"
|
26
|
+
#include "misc.h"
|
27
|
+
#include "random.h"
|
28
|
+
#include "sha1.h"
|
29
|
+
#include "sha2.h"
|
30
|
+
#include "siphash.h"
|
31
|
+
#include "xor-crypt.h"
|
32
|
+
|
33
|
+
#if defined(DEBUG) && DEBUG == 1
|
34
|
+
#define bscrypt_test() \
|
35
|
+
{ \
|
36
|
+
bscrypt_test_sha1(); \
|
37
|
+
bscrypt_test_sha2(); \
|
38
|
+
bscrypt_test_base64(); \
|
39
|
+
bscrypt_test_random(); \
|
40
|
+
bscrypt_test_siphash(); \
|
41
|
+
}
|
42
|
+
#else
|
43
|
+
#define bscrypt_test() \
|
44
|
+
fprintf(stderr, \
|
45
|
+
"Debug mode not enabled, define DEBUG as 1 in the compiler.\n");
|
46
|
+
#endif
|
47
|
+
|
48
|
+
/* end include gate */
|
49
|
+
#endif
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
def check_for_stdatomics
|
4
|
+
RbConfig::MAKEFILE_CONFIG['CC'] = $CC = ENV['CC'] if ENV['CC']
|
5
|
+
RbConfig::MAKEFILE_CONFIG['CPP'] = $CPP = ENV['CPP'] if ENV['CPP']
|
6
|
+
puts 'Missing support for atomic operations (support for C11) - is your compiler updated?' unless have_header('stdatomic.h')
|
7
|
+
end
|
8
|
+
|
9
|
+
abort 'Missing a Linux/Unix OS evented API (epoll/kqueue).' unless have_func('kevent') || have_func('epoll_ctl')
|
10
|
+
|
11
|
+
if ENV['CC']
|
12
|
+
ENV['CPP'] ||= ENV['CC']
|
13
|
+
puts "detected user prefered compiler (#{ENV['CC']})."
|
14
|
+
check_for_stdatomics
|
15
|
+
elsif find_executable('clang') && puts('testing clang for stdatomic support...').nil? && system("printf \"\#include <stdatomic.h>\nint main(void) {}\" | clang -include stdatomic.h -xc -o /dev/null -", out: '/dev/null')
|
16
|
+
$CC = ENV['CC'] = 'clang'
|
17
|
+
$CPP = ENV['CPP'] = 'clang'
|
18
|
+
puts "using clang compiler v. #{`clang -dumpversion`}."
|
19
|
+
elsif find_executable('gcc-6')
|
20
|
+
$CC = ENV['CC'] = 'gcc-6'
|
21
|
+
$CPP = ENV['CPP'] = find_executable('g++-6') ? 'g++-6' : 'gcc-6'
|
22
|
+
puts 'using gcc-6 compiler.'
|
23
|
+
elsif find_executable('gcc-5')
|
24
|
+
$CC = ENV['CC'] = 'gcc-5'
|
25
|
+
$CPP = ENV['CPP'] = find_executable('g++-5') ? 'g++-5' : 'gcc-5'
|
26
|
+
puts 'using gcc-5 compiler.'
|
27
|
+
elsif find_executable('gcc-4.9')
|
28
|
+
$CC = ENV['CC'] = 'gcc-4.9'
|
29
|
+
$CPP = ENV['CPP'] = find_executable('g++-4.9') ? 'g++-4.9' : 'gcc-4.9'
|
30
|
+
puts 'using gcc-4.9 compiler.'
|
31
|
+
else
|
32
|
+
check_for_stdatomics
|
33
|
+
end
|
34
|
+
|
35
|
+
$CFLAGS = '-std=c11 -O3 -Wall'
|
36
|
+
RbConfig::MAKEFILE_CONFIG['CC'] = $CC = ENV['CC'] if ENV['CC']
|
37
|
+
RbConfig::MAKEFILE_CONFIG['CPP'] = $CPP = ENV['CPP'] if ENV['CPP']
|
38
|
+
|
39
|
+
# abort "Missing OpenSSL." unless have_library("ssl")
|
40
|
+
|
41
|
+
create_makefile 'iodine/iodine'
|
data/ext/iodine/hex.c
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
/*
|
2
|
+
(un)copyright: Boaz segev, 2016
|
3
|
+
License: Public Domain except for any non-public-domain algorithms, which are
|
4
|
+
subject to their own licenses.
|
5
|
+
|
6
|
+
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
|
+
*/
|
8
|
+
#ifndef _GNU_SOURCE
|
9
|
+
#define _GNU_SOURCE
|
10
|
+
#endif
|
11
|
+
#include "hex.h"
|
12
|
+
#include <ctype.h>
|
13
|
+
|
14
|
+
/* ***************************************************************************
|
15
|
+
Hex Conversion
|
16
|
+
*/
|
17
|
+
|
18
|
+
/*
|
19
|
+
#define hex2i(h) \
|
20
|
+
(((h) >= '0' && (h) <= '9') ? ((h) - '0') : (((h) | 32) - 'a' + 10))
|
21
|
+
*/
|
22
|
+
|
23
|
+
#define i2hex(hi) (((hi) < 10) ? ('0' + (hi)) : ('A' + ((hi)-10)))
|
24
|
+
|
25
|
+
/* Credit to Jonathan Leffler for the idea */
|
26
|
+
#define hex2i(c) \
|
27
|
+
(((c) >= '0' && (c) <= '9') ? ((c)-48) : (((c) >= 'a' && (c) <= 'f') || \
|
28
|
+
((c) >= 'A' && (c) <= 'F')) \
|
29
|
+
? (((c) | 32) - 87) \
|
30
|
+
: ({ \
|
31
|
+
return -1; \
|
32
|
+
0; \
|
33
|
+
}))
|
34
|
+
|
35
|
+
/**
|
36
|
+
Returns 1 if the string is HEX encoded (no non-valid hex values). Returns 0 if
|
37
|
+
it isn't.
|
38
|
+
*/
|
39
|
+
int bscrypt_is_hex(const char *string, size_t length) {
|
40
|
+
// for (size_t i = 0; i < length; i++) {
|
41
|
+
// if (isxdigit(string[i]) == 0)
|
42
|
+
// return 0;
|
43
|
+
char c;
|
44
|
+
for (size_t i = 0; i < length; i++) {
|
45
|
+
c = string[i];
|
46
|
+
if ((!isspace(c)) &&
|
47
|
+
(c < '0' || c > 'z' ||
|
48
|
+
!((c >= 'a') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))))
|
49
|
+
return 0;
|
50
|
+
}
|
51
|
+
return 1;
|
52
|
+
}
|
53
|
+
/**
|
54
|
+
This will convert the string (byte stream) to a Hex string. This is not
|
55
|
+
cryptography, just conversion for pretty print.
|
56
|
+
|
57
|
+
The target buffer MUST have enough room for the expected data. The expected
|
58
|
+
data is double the length of the string + 1 byte for the NULL terminator
|
59
|
+
byte.
|
60
|
+
|
61
|
+
A NULL byte will be appended to the target buffer. The function will return
|
62
|
+
the number of bytes written to the target buffer.
|
63
|
+
|
64
|
+
Returns the number of bytes actually written to the target buffer (excluding
|
65
|
+
the NULL terminator byte).
|
66
|
+
*/
|
67
|
+
int bscrypt_str2hex(char *target, const char *string, size_t length) {
|
68
|
+
if (!target)
|
69
|
+
return -1;
|
70
|
+
size_t i = length;
|
71
|
+
target[(length << 1) + 1] = 0;
|
72
|
+
// go in reverse, so that target could be same as string.
|
73
|
+
while (i) {
|
74
|
+
--i;
|
75
|
+
target[(i << 1) + 1] = i2hex(string[i] & 0x0F);
|
76
|
+
target[(i << 1)] = i2hex(((uint8_t *)string)[i] >> 4);
|
77
|
+
}
|
78
|
+
return (length << 1);
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
This will convert a Hex string to a byte string. This is not cryptography,
|
83
|
+
just conversion for pretty print.
|
84
|
+
|
85
|
+
The target buffer MUST have enough room for the expected data. The expected
|
86
|
+
data is half the length of the Hex string + 1 byte for the NULL terminator
|
87
|
+
byte.
|
88
|
+
|
89
|
+
A NULL byte will be appended to the target buffer. The function will return
|
90
|
+
the number of bytes written to the target buffer.
|
91
|
+
|
92
|
+
If the target buffer is NULL, the encoded string will be destructively
|
93
|
+
edited
|
94
|
+
and the decoded data will be placed in the original string's buffer.
|
95
|
+
|
96
|
+
Returns the number of bytes actually written to the target buffer (excluding
|
97
|
+
the NULL terminator byte).
|
98
|
+
*/
|
99
|
+
int bscrypt_hex2str(char *target, char *hex, size_t length) {
|
100
|
+
if (!target)
|
101
|
+
target = hex;
|
102
|
+
size_t i = 0;
|
103
|
+
size_t written = 0;
|
104
|
+
while (i + 1 < length) {
|
105
|
+
if (isspace(hex[i])) {
|
106
|
+
++i;
|
107
|
+
continue;
|
108
|
+
}
|
109
|
+
target[written] = (hex2i(hex[i]) << 4) | hex2i(hex[i + 1]);
|
110
|
+
++written;
|
111
|
+
i += 2;
|
112
|
+
}
|
113
|
+
if (i < length && !isspace(hex[i])) {
|
114
|
+
target[written] = hex2i(hex[i + 1]);
|
115
|
+
++written;
|
116
|
+
}
|
117
|
+
|
118
|
+
target[written] = 0;
|
119
|
+
return written;
|
120
|
+
}
|
121
|
+
|
122
|
+
#undef hex2i
|
123
|
+
#undef i2hex
|
data/ext/iodine/hex.h
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
/*
|
2
|
+
(un)copyright: Boaz segev, 2016
|
3
|
+
License: Public Domain except for any non-public-domain algorithms, which are
|
4
|
+
subject to their own licenses.
|
5
|
+
|
6
|
+
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
|
+
*/
|
8
|
+
#ifndef bscrypt_HEX_H
|
9
|
+
#define bscrypt_HEX_H
|
10
|
+
#include "bscrypt-common.h"
|
11
|
+
/* *****************************************************************************
|
12
|
+
C++ extern
|
13
|
+
*/
|
14
|
+
#if defined(__cplusplus)
|
15
|
+
extern "C" {
|
16
|
+
#endif
|
17
|
+
|
18
|
+
/* ***************************************************************************
|
19
|
+
Hex Conversion
|
20
|
+
*/
|
21
|
+
|
22
|
+
/**
|
23
|
+
Returns 1 if the string is HEX encoded (no non-valid hex values). Returns 0 if
|
24
|
+
it isn't.
|
25
|
+
*/
|
26
|
+
int bscrypt_is_hex(const char *string, size_t length);
|
27
|
+
/**
|
28
|
+
This will convert the string (byte stream) to a Hex string. This is not
|
29
|
+
cryptography, just conversion for pretty print.
|
30
|
+
|
31
|
+
The target buffer MUST have enough room for the expected data. The expected
|
32
|
+
data is double the length of the string + 1 byte for the NULL terminator
|
33
|
+
byte.
|
34
|
+
|
35
|
+
A NULL byte will be appended to the target buffer. The function will return
|
36
|
+
the number of bytes written to the target buffer.
|
37
|
+
|
38
|
+
Returns the number of bytes actually written to the target buffer (excluding
|
39
|
+
the NULL terminator byte).
|
40
|
+
*/
|
41
|
+
int bscrypt_str2hex(char *target, const char *string, size_t length);
|
42
|
+
|
43
|
+
/**
|
44
|
+
This will convert a Hex string to a byte string. This is not cryptography,
|
45
|
+
just conversion for pretty print.
|
46
|
+
|
47
|
+
The target buffer MUST have enough room for the expected data. The expected
|
48
|
+
data is half the length of the Hex string + 1 byte for the NULL terminator
|
49
|
+
byte.
|
50
|
+
|
51
|
+
A NULL byte will be appended to the target buffer. The function will return
|
52
|
+
the number of bytes written to the target buffer.
|
53
|
+
|
54
|
+
If the target buffer is NULL, the encoded string will be destructively
|
55
|
+
edited
|
56
|
+
and the decoded data will be placed in the original string's buffer.
|
57
|
+
|
58
|
+
Returns the number of bytes actually written to the target buffer (excluding
|
59
|
+
the NULL terminator byte).
|
60
|
+
*/
|
61
|
+
int bscrypt_hex2str(char *target, char *hex, size_t length);
|
62
|
+
|
63
|
+
/* *****************************************************************************
|
64
|
+
C++ extern finish
|
65
|
+
*/
|
66
|
+
#if defined(__cplusplus)
|
67
|
+
}
|
68
|
+
#endif
|
69
|
+
|
70
|
+
#endif
|
data/ext/iodine/http.c
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
#include "http.h"
|
2
|
+
|
3
|
+
/**
|
4
|
+
A faster (yet less localized) alternative to `gmtime_r`.
|
5
|
+
|
6
|
+
See the libc `gmtime_r` documentation for details.
|
7
|
+
|
8
|
+
Falls back to `gmtime_r` for dates before epoch.
|
9
|
+
*/
|
10
|
+
struct tm* http_gmtime(const time_t* timer, struct tm* tmbuf) {
|
11
|
+
// static char* DAYS[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
12
|
+
// static char * Months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
13
|
+
// "Jul",
|
14
|
+
// "Aug", "Sep", "Oct", "Nov", "Dec"};
|
15
|
+
static uint8_t month_len[] = {
|
16
|
+
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, // nonleap year
|
17
|
+
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // leap year
|
18
|
+
};
|
19
|
+
if (*timer < 0)
|
20
|
+
return gmtime_r(timer, tmbuf);
|
21
|
+
ssize_t tmp;
|
22
|
+
tmbuf->tm_gmtoff = 0;
|
23
|
+
tmbuf->tm_zone = "UTC";
|
24
|
+
tmbuf->tm_isdst = 0;
|
25
|
+
tmbuf->tm_year = 70; // tm_year == The number of years since 1900
|
26
|
+
tmbuf->tm_mon = 0;
|
27
|
+
// for seconds up to weekdays, we build up, as small values clean up larger
|
28
|
+
// values.
|
29
|
+
tmp = ((ssize_t)*timer);
|
30
|
+
tmbuf->tm_sec = tmp % 60;
|
31
|
+
tmp = tmp / 60;
|
32
|
+
tmbuf->tm_min = tmp % 60;
|
33
|
+
tmp = tmp / 60;
|
34
|
+
tmbuf->tm_hour = tmp % 24;
|
35
|
+
tmp = tmp / 24;
|
36
|
+
// day of epoch was a thursday. Add + 3 so sunday == 0...
|
37
|
+
tmbuf->tm_wday = (tmp + 3) % 7;
|
38
|
+
// tmp == number of days since epoch
|
39
|
+
#define DAYS_PER_400_YEARS ((400 * 365) + 97)
|
40
|
+
while (tmp >= DAYS_PER_400_YEARS) {
|
41
|
+
tmbuf->tm_year += 400;
|
42
|
+
tmp -= DAYS_PER_400_YEARS;
|
43
|
+
}
|
44
|
+
#undef DAYS_PER_400_YEARS
|
45
|
+
#define DAYS_PER_100_YEARS ((100 * 365) + 24)
|
46
|
+
while (tmp >= DAYS_PER_100_YEARS) {
|
47
|
+
tmbuf->tm_year += 100;
|
48
|
+
tmp -= DAYS_PER_100_YEARS;
|
49
|
+
if (((tmbuf->tm_year / 100) & 3) ==
|
50
|
+
0) // leap century divisable by 400 => add leap
|
51
|
+
--tmp;
|
52
|
+
}
|
53
|
+
#undef DAYS_PER_100_YEARS
|
54
|
+
#define DAYS_PER_32_YEARS ((32 * 365) + 8)
|
55
|
+
while (tmp >= DAYS_PER_32_YEARS) {
|
56
|
+
tmbuf->tm_year += 32;
|
57
|
+
tmp -= DAYS_PER_32_YEARS;
|
58
|
+
}
|
59
|
+
#undef DAYS_PER_32_YEARS
|
60
|
+
#define DAYS_PER_8_YEARS ((8 * 365) + 2)
|
61
|
+
while (tmp >= DAYS_PER_8_YEARS) {
|
62
|
+
tmbuf->tm_year += 8;
|
63
|
+
tmp -= DAYS_PER_8_YEARS;
|
64
|
+
}
|
65
|
+
#undef DAYS_PER_8_YEARS
|
66
|
+
#define DAYS_PER_4_YEARS ((4 * 365) + 1)
|
67
|
+
while (tmp >= DAYS_PER_4_YEARS) {
|
68
|
+
tmbuf->tm_year += 4;
|
69
|
+
tmp -= DAYS_PER_4_YEARS;
|
70
|
+
}
|
71
|
+
#undef DAYS_PER_4_YEARS
|
72
|
+
while (tmp >= 365) {
|
73
|
+
tmbuf->tm_year += 1;
|
74
|
+
tmp -= 365;
|
75
|
+
if ((tmbuf->tm_year & 3) == 0) { // leap year
|
76
|
+
if (tmp > 0) {
|
77
|
+
--tmp;
|
78
|
+
continue;
|
79
|
+
} else {
|
80
|
+
tmp += 365;
|
81
|
+
--tmbuf->tm_year;
|
82
|
+
break;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
tmbuf->tm_yday = tmp;
|
87
|
+
if ((tmbuf->tm_year & 3) == 1) {
|
88
|
+
// regular year
|
89
|
+
for (size_t i = 0; i < 12; i++) {
|
90
|
+
if (tmp < month_len[i])
|
91
|
+
break;
|
92
|
+
tmp -= month_len[i];
|
93
|
+
++tmbuf->tm_mon;
|
94
|
+
}
|
95
|
+
} else {
|
96
|
+
// leap year
|
97
|
+
for (size_t i = 12; i < 24; i++) {
|
98
|
+
if (tmp < month_len[i])
|
99
|
+
break;
|
100
|
+
tmp -= month_len[i];
|
101
|
+
++tmbuf->tm_mon;
|
102
|
+
}
|
103
|
+
}
|
104
|
+
tmbuf->tm_mday = tmp;
|
105
|
+
return tmbuf;
|
106
|
+
}
|
107
|
+
|
108
|
+
static char* DAY_NAMES[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
109
|
+
static char* MONTH_NAMES[] = {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
|
110
|
+
"Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "};
|
111
|
+
static const char* GMT_STR = "GMT";
|
112
|
+
|
113
|
+
size_t http_date2str(char* target, struct tm* tmbuf) {
|
114
|
+
char* pos = target;
|
115
|
+
uint16_t tmp;
|
116
|
+
*(uint32_t*)pos = *((uint32_t*)DAY_NAMES[tmbuf->tm_wday]);
|
117
|
+
pos[3] = ',';
|
118
|
+
pos[4] = ' ';
|
119
|
+
pos += 5;
|
120
|
+
if (tmbuf->tm_mday < 10) {
|
121
|
+
*pos = '0' + tmbuf->tm_mday;
|
122
|
+
++pos;
|
123
|
+
} else {
|
124
|
+
tmp = tmbuf->tm_mday / 10;
|
125
|
+
pos[0] = '0' + tmp;
|
126
|
+
pos[1] = '0' + (tmbuf->tm_mday - (tmp * 10));
|
127
|
+
pos += 2;
|
128
|
+
}
|
129
|
+
*(pos++) = ' ';
|
130
|
+
*(uint32_t*)pos = *((uint32_t*)MONTH_NAMES[tmbuf->tm_mon]);
|
131
|
+
pos += 4;
|
132
|
+
// write year.
|
133
|
+
pos += http_ul2a(pos, tmbuf->tm_year + 1900);
|
134
|
+
*(pos++) = ' ';
|
135
|
+
tmp = tmbuf->tm_hour / 10;
|
136
|
+
pos[0] = '0' + tmp;
|
137
|
+
pos[1] = '0' + (tmbuf->tm_hour - (tmp * 10));
|
138
|
+
pos[2] = ':';
|
139
|
+
tmp = tmbuf->tm_min / 10;
|
140
|
+
pos[3] = '0' + tmp;
|
141
|
+
pos[4] = '0' + (tmbuf->tm_min - (tmp * 10));
|
142
|
+
pos[5] = ':';
|
143
|
+
tmp = tmbuf->tm_sec / 10;
|
144
|
+
pos[6] = '0' + tmp;
|
145
|
+
pos[7] = '0' + (tmbuf->tm_sec - (tmp * 10));
|
146
|
+
pos += 8;
|
147
|
+
pos[0] = ' ';
|
148
|
+
*((uint32_t*)(pos + 1)) = *((uint32_t*)GMT_STR);
|
149
|
+
pos += 4;
|
150
|
+
return pos - target;
|
151
|
+
}
|
152
|
+
|
153
|
+
/* Credit to Jonathan Leffler for the idea of a unified conditional */
|
154
|
+
#define hex_val(c) \
|
155
|
+
(((c) >= '0' && (c) <= '9') ? ((c)-48) : (((c) >= 'a' && (c) <= 'f') || \
|
156
|
+
((c) >= 'A' && (c) <= 'F')) \
|
157
|
+
? (((c) | 32) - 87) \
|
158
|
+
: ({ \
|
159
|
+
return -1; \
|
160
|
+
0; \
|
161
|
+
}))
|
162
|
+
ssize_t http_decode_url(char* dest, const char* url_data, size_t length) {
|
163
|
+
char* pos = dest;
|
164
|
+
const char* end = url_data + length;
|
165
|
+
while (url_data < end) {
|
166
|
+
if (*url_data == '+') {
|
167
|
+
// decode space
|
168
|
+
*(pos++) = ' ';
|
169
|
+
++url_data;
|
170
|
+
} else if (*url_data == '%') {
|
171
|
+
// decode hex value
|
172
|
+
// this is a percent encoded value.
|
173
|
+
*(pos++) = (hex_val(url_data[1]) << 4) | hex_val(url_data[2]);
|
174
|
+
url_data += 3;
|
175
|
+
} else
|
176
|
+
*(pos++) = *(url_data++);
|
177
|
+
}
|
178
|
+
*pos = 0;
|
179
|
+
return pos - dest;
|
180
|
+
}
|
181
|
+
|
182
|
+
ssize_t http_decode_url_unsafe(char* dest, const char* url_data) {
|
183
|
+
char* pos = dest;
|
184
|
+
while (*url_data) {
|
185
|
+
if (*url_data == '+') {
|
186
|
+
// decode space
|
187
|
+
*(pos++) = ' ';
|
188
|
+
++url_data;
|
189
|
+
} else if (*url_data == '%') {
|
190
|
+
// decode hex value
|
191
|
+
// this is a percent encoded value.
|
192
|
+
*(pos++) = (hex_val(url_data[1]) << 4) | hex_val(url_data[2]);
|
193
|
+
url_data += 3;
|
194
|
+
} else
|
195
|
+
*(pos++) = *(url_data++);
|
196
|
+
}
|
197
|
+
*pos = 0;
|
198
|
+
return pos - dest;
|
199
|
+
}
|
200
|
+
#undef hex_val
|