1 #include "netheaders.h"
11 mem_calloc(size_t nmemb
, size_t size
)
15 ret
= calloc(nmemb
, size
);
17 log_fatal("mem_calloc: alloc failed");
23 mem_malloc(size_t size
)
29 log_fatal("mem_malloc: alloc failed");
35 mem_strdup(const char *str
)
41 log_fatal("mem_strdup: alloc failed");
47 mem_strdup_n(const char *str
, size_t n
)
51 ret
= mem_calloc(1, n
+ 1);
53 log_fatal("mem_strdup: alloc failed");
67 add_token(const char *buf
, size_t len
, struct token_list
*tokens
)
71 token
= mem_calloc(1, sizeof(*token
));
72 token
->token
= mem_strdup_n(buf
, len
);
73 TAILQ_INSERT_TAIL(tokens
, token
, next
);
76 /* this isn't very fast, but this thing is meant for a single user anyhow */
78 tokenize(const char *buf
, const char *sep
, int lim
,
79 struct token_list
*tokens
)
87 while ((lim
< 0 || ntok
< (size_t)lim
) && (p
= strpbrk(buf
, sep
))) {
89 add_token(buf
, len
, tokens
);
94 /* add any remaining */
96 add_token(buf
, strlen(buf
), tokens
);
104 token_list_clear(struct token_list
*tokens
)
108 while ((token
= TAILQ_FIRST(tokens
))) {
109 TAILQ_REMOVE(tokens
, token
, next
);
111 mem_free(token
->token
);
117 get_int(const char *buf
, int base
)
122 rv
= evutil_strtoll(buf
, &endp
, base
);
130 get_port(const char *str
)
136 port
= strtol(str
, &endp
, 10);
137 if (errno
== ERANGE
|| !endp
|| *endp
!= '\0' ||
138 port
< 1 || port
> 0xffff)
144 // tokenize a CONNECT host:port request
146 url_connect_tokenize(const char *str
)
152 url
= mem_calloc(1, sizeof(*url
));
154 p
= strrchr(str
, ':');
157 port
= get_port(p
+ 1);
161 url
->host
= mem_strdup_n(str
, p
- str
);
172 // XXX should this do more to sanitize the url?
174 url_tokenize(const char *str
)
179 struct token_list tokens
;
180 struct token
*scheme
, *slash
, *hostport
, *path
;
188 ntokens
= tokenize(str
, "/", 3, &tokens
);
191 if (ntokens
>= 1 && TAILQ_FIRST(&tokens
)->token
[0] == '\0') {
192 url
= mem_calloc(1, sizeof(*url
));
193 url
->path
= mem_strdup(str
);
200 scheme
= TAILQ_FIRST(&tokens
);
201 len
= strlen(scheme
->token
);
202 if (len
< 2 || scheme
->token
[len
- 1] != ':')
204 scheme
->token
[len
- 1] = '\0';
206 slash
= TAILQ_NEXT(scheme
, next
);
207 if (slash
->token
[0] != '\0')
210 hostport
= TAILQ_NEXT(slash
, next
);
211 if (hostport
->token
[0] == '\0')
213 // XXX this could break IPv6 addresses
214 p
= strrchr(hostport
->token
, ':');
215 if (p
== hostport
->token
)
217 if (p
&& p
[1] != '\0') {
225 // XXX maybe urlencode?
226 assert(ntokens
== 4);
227 path
= TAILQ_NEXT(hostport
, next
);
228 len
= strlen(path
->token
);
229 pathstr
= mem_calloc(1, 2 + len
);
231 memcpy(pathstr
+ 1, path
->token
, len
);
233 pathstr
= mem_strdup("/");
236 url
= mem_calloc(1, sizeof(*url
));
237 url
->scheme
= scheme
->token
;
238 url
->host
= hostport
->token
;
242 scheme
->token
= NULL
;
243 hostport
->token
= NULL
;
246 token_list_clear(&tokens
);
252 url_free(struct url
*url
)
257 mem_free(url
->scheme
);
264 format_addr(const struct sockaddr
*addr
)
266 const char *r
= NULL
;
267 static char buf
[256];
270 if (addr
->sa_family
== AF_INET
) {
271 struct sockaddr_in
*sin
= (struct sockaddr_in
*)addr
;
272 r
= evutil_inet_ntop(AF_INET
, &sin
->sin_addr
, tmp
,
276 evutil_snprintf(buf
, sizeof(buf
), "%s:%hu",
277 tmp
, ntohs(sin
->sin_port
));
281 } else if (addr
->sa_family
== AF_INET6
) {
282 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)addr
;
283 r
= evutil_inet_ntop(AF_INET6
, &sin6
->sin6_addr
, tmp
,
287 evutil_snprintf(buf
, sizeof(buf
), "[%s]:%hu",
288 tmp
, ntohs(sin6
->sin6_port
));
301 socket_error_string(evutil_socket_t s
)
303 return evutil_socket_error_to_string(evutil_socket_geterror(s
));
310 int main(int argc
, char **argv
)
314 url
= url_tokenize(argv
[1]);
316 printf("bad url!\n");
319 printf("%s, %s, %d, %s\n",
320 url
->scheme
, url
->host
, url
->port
, url
->path
);