diff options
author | Eduardo Chappa <chappa@washington.edu> | 2021-07-30 09:00:04 -0600 |
---|---|---|
committer | Eduardo Chappa <chappa@washington.edu> | 2021-07-30 09:00:04 -0600 |
commit | bba1f63e9be0b65c090d1707a6c9168443604ed6 (patch) | |
tree | 7dc6534d6693936d1249f81e790f264750d5e248 /imap/src/c-client | |
parent | c39814e31d89bd14111347aadca9f0e225b8f06d (diff) | |
download | alpine-bba1f63e9be0b65c090d1707a6c9168443604ed6.tar.xz |
* Improvements to the http and json code.
Diffstat (limited to 'imap/src/c-client')
-rw-r--r-- | imap/src/c-client/http.c | 106 | ||||
-rw-r--r-- | imap/src/c-client/http.h | 20 | ||||
-rw-r--r-- | imap/src/c-client/json.c | 46 | ||||
-rw-r--r-- | imap/src/c-client/json.h | 18 | ||||
-rw-r--r-- | imap/src/c-client/oauth2_aux.c | 72 |
5 files changed, 114 insertions, 148 deletions
diff --git a/imap/src/c-client/http.c b/imap/src/c-client/http.c index 0162502d..e158db37 100644 --- a/imap/src/c-client/http.c +++ b/imap/src/c-client/http.c @@ -21,15 +21,6 @@ unsigned long http_debug; static char http_notok[] = "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\40\42\50\51\54\57\72\73\74\75\76\77\100\133\134\135\173\175\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"; static char http_noparam_val[] = "\1\2\3\4\5\6\7\10\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\42\134\177"; -#define HTTPTCPPORT (long) 80 /* assigned TCP contact port */ -#define HTTPSSLPORT (long) 443 /* assigned SSL TCP contact port */ - -typedef struct http_request_s { - unsigned char *request; - unsigned char *header; - unsigned char *body; -} HTTP_REQUEST_S; - #define HTP_NOVAL 0x001 /* the header accepts parameters without value */ #define HTP_UNLIMITED (-1) /* parse and infinite list */ @@ -96,20 +87,12 @@ typedef struct http_header_data_s { /* helper functions */ HTTP_STATUS_S *http_status_line_get(unsigned char *); void http_status_line_free(HTTP_STATUS_S **); -HTTP_REQUEST_S *http_request_get(void); -void http_request_free(HTTP_REQUEST_S **); -unsigned char *http_request_line(unsigned char *, unsigned char *, unsigned char *); -void http_add_header(HTTP_REQUEST_S **, unsigned char *, unsigned char *); void http_add_body(HTTP_REQUEST_S **, unsigned char *); void buffer_add(unsigned char **, unsigned char *); unsigned char *hex_escape_url_part(unsigned char *, unsigned char *); unsigned char *encode_url_body_part(unsigned char *, unsigned char *); -unsigned char *http_response_from_reply(HTTPSTREAM *); /* HTTP function prototypes */ -int http_valid_net_parse (unsigned char *, NETMBX *); - -long http_send (HTTPSTREAM *, HTTP_REQUEST_S *); long http_reply (HTTPSTREAM *); long http_fake (HTTPSTREAM *, unsigned char *); @@ -147,28 +130,15 @@ http_parameters (long function,void *value) unsigned char * http_response_from_reply(HTTPSTREAM *stream) { - unsigned char *rv = NULL, *s, *t; + unsigned char *rv = NULL, *s; if(stream == NULL || stream->reply == NULL || stream->header == NULL) return rv; - if(stream->header->content_length){ - s = strstr(stream->reply, "\r\n\r\n"); - if(s != NULL) rv = s + 4; - } - else if (stream->header->transfer_encoding){ - HTTP_PARAM_LIST_S *p = stream->header->transfer_encoding->p; - for(; p ; p = p->next){ - if(!compare_cstring(p->vp->value, "chunked")) - break; - } - if(p && p->vp->value){ /* chunked transfer */ - if((s = strstr(stream->reply, "\r\n\r\n")) != NULL - && (t = strstr(s + 4, "\r\n")) != NULL) - rv = t + 2; - } - } - return rv; + s = strstr(stream->reply, "\r\n\r\n"); + if(s != NULL) rv = s + 4; + + return s ? rv : NIL; } void @@ -996,54 +966,19 @@ http_post_param(HTTPSTREAM *stream, HTTP_PARAM_S *param) } unsigned char * -http_post_param2(HTTPSTREAM *stream, HTTP_PARAM_S *param) +http_get(HTTPSTREAM *stream, HTTP_PARAM_S **h) { - HTTP_PARAM_S enc_param; - HTTP_REQUEST_S *http_request = NULL; - unsigned char *response = NULL; - int i; - - if(stream == NULL || param == NULL) return response; - - http_request = http_request_get(); - http_request->request = http_request_line("POST", stream->urltail, HTTP_1_1_VERSION); - http_add_header(&http_request, "Host", stream->urlhost); - http_add_header(&http_request, "User-Agent", "Alpine"); - http_add_header(&http_request, "Content-Type", HTTP_MIME_URLENCODED); - - for(i = 0; param[i].name != NULL; i++){ - enc_param.name = encode_url_body_part(param[i].name, NULL); - enc_param.value = encode_url_body_part(param[i].value, NULL); - if(i > 0) - http_add_body(&http_request, "&"); - http_add_body(&http_request, enc_param.name); - http_add_body(&http_request, "="); - http_add_body(&http_request, enc_param.value); - fs_give((void **) &enc_param.name); - fs_give((void **) &enc_param.value); - } - - if(http_send(stream, http_request)){ - unsigned char *s = http_response_from_reply(stream); - response = cpystr(s ? (char *) s : ""); - } - - http_request_free(&http_request); - - return response; -} - -unsigned char * -http_get(HTTPSTREAM *stream) -{ HTTP_REQUEST_S *http_request; unsigned char *response = NIL; + int i; if(!stream) return response; http_request = http_request_get(); http_request->request = http_request_line("GET", stream->urltail, HTTP_1_1_VERSION); http_add_header(&http_request, "Host", stream->urlhost); + for(i = 0; h && h[i]->name && h[i]->value; i++) + http_add_header(&http_request, h[i]->name, h[i]->value); if(http_send(stream, http_request)){ unsigned char *s = http_response_from_reply(stream); @@ -1146,7 +1081,7 @@ http_reply (HTTPSTREAM *stream) if (stream->response) fs_give ((void **) &stream->response); stream->response = (unsigned char *) net_getline(stream->netstream); - if(stream->debug) mm_log(stream->response, HTTPDEBUG); + if(stream->debug) mm_log(stream->response ? stream->response : (unsigned char *) "<NIL RESPONSE>", HTTPDEBUG); if(stream->response){ buffer_add(&stream->reply, stream->response); @@ -1192,22 +1127,21 @@ http_reply (HTTPSTREAM *stream) break; } if(p && p->vp->value){ /* chunked transfer */ - int done = 0; - size = 0L; - while(!done){ - if (stream->response) fs_give ((void **) &stream->response); - stream->response = (unsigned char *) net_getline (stream->netstream); - if(stream->response){ - buffer_add(&stream->reply, stream->response); - buffer_add(&stream->reply, "\015\012"); - size = strtol((unsigned char *) stream->response, NIL, 16); + unsigned char *s = NIL; + do { + if (s) fs_give ((void **) &s); + size = 0L; + if((s = (unsigned char *) net_getline (stream->netstream)) != NIL){ +// buffer_add(&stream->reply, s); +// buffer_add(&stream->reply, "\015\012"); + if(stream->debug) mm_log(s, HTTPDEBUG); + size = strtol(s, NIL, 16); fs_give ((void **) &stream->response); stream->response = (unsigned char *) net_getsize (stream->netstream, size); buffer_add(&stream->reply, stream->response); if(stream->debug) mm_log(stream->response, HTTPDEBUG); } - if(size == 0L) done++; - } + } while (stream && stream->netstream && s && (size > 0 || !*s )); } } diff --git a/imap/src/c-client/http.h b/imap/src/c-client/http.h index 1ddc988b..4e1f55b1 100644 --- a/imap/src/c-client/http.h +++ b/imap/src/c-client/http.h @@ -11,6 +11,9 @@ * */ +#define HTTPTCPPORT (long) 80 /* assigned TCP contact port */ +#define HTTPSSLPORT (long) 443 /* assigned SSL TCP contact port */ + typedef struct http_val_param_s { char *value; PARAMETER *plist; @@ -105,11 +108,24 @@ typedef struct http_param_s { char *value; } HTTP_PARAM_S; +typedef struct http_request_s { + unsigned char *request; + unsigned char *header; + unsigned char *body; +} HTTP_REQUEST_S; + /* exported prototypes */ +HTTP_REQUEST_S *http_request_get(void); +void http_request_free(HTTP_REQUEST_S **); +unsigned char *http_request_line(unsigned char *, unsigned char *, unsigned char *); +void http_add_header(HTTP_REQUEST_S **, unsigned char *, unsigned char *); +unsigned char *http_response_from_reply(HTTPSTREAM *); + +int http_valid_net_parse (unsigned char *, NETMBX *); HTTPSTREAM *http_open (unsigned char *); +long http_send (HTTPSTREAM *, HTTP_REQUEST_S *); unsigned char *http_post_param(HTTPSTREAM *, HTTP_PARAM_S *); -unsigned char *http_post_param2(HTTPSTREAM *, HTTP_PARAM_S *); -unsigned char *http_get(HTTPSTREAM *); +unsigned char *http_get(HTTPSTREAM *, HTTP_PARAM_S **); void http_close (HTTPSTREAM *stream); HTTP_PARAM_S *http_param_get(int); diff --git a/imap/src/c-client/json.c b/imap/src/c-client/json.c index d19e99d6..245cb48c 100644 --- a/imap/src/c-client/json.c +++ b/imap/src/c-client/json.c @@ -216,7 +216,7 @@ json_value_parse(unsigned char **s) w = *s; json_skipws(w); jx = fs_get(sizeof(JSON_X)); - memset((void **) jx, 0, sizeof(JSON_X)); + memset((void *) jx, 0, sizeof(JSON_X)); jx->jtype = JEnd; switch(*w){ case '\"': jx->jtype = JString; break; @@ -261,7 +261,7 @@ json_value_parse(unsigned char **s) } break; - case JObject: jx->value = (void *) json_parse(&w); + case JObject: jx->value = (void *) json_parse_work(&w); break; case JLong : l = fs_get(sizeof(unsigned long)); @@ -322,12 +322,13 @@ JSON_S * json_array_parse_work(unsigned char **s) { unsigned char *w = *s; - JSON_S *j; + JSON_S *j = NIL; json_skipws(w); j = fs_get(sizeof(JSON_S)); memset((void *) j, 0, sizeof(JSON_S)); - j->value = json_value_parse(&w); + if(*w != ']') + j->value = json_value_parse(&w); json_skipws(w); switch(*w){ case ',' : json_skipchar(w); @@ -421,7 +422,13 @@ json_free(JSON_S **jp) } JSON_S * -json_parse(unsigned char **s) +json_parse(unsigned char *s) +{ + return json_parse_work(&s); +} + +JSON_S * +json_parse_work(unsigned char **s) { JSON_S *j = NULL; JSON_X *jx; @@ -447,3 +454,32 @@ json_parse(unsigned char **s) *s = w; return j; } + +void +json_assign(void **v, JSON_S *j, char *s, JObjType t) +{ + JSON_X *jx = json_body_value(j, s); + long l; + unsigned long ul; + int i; + + if(jx && jx->jtype == t && jx->value){ + switch(t){ /* override here */ + case JString : *v = (void *) cpystr((char *) jx->value); break; + default : break; + } + } +} + +JSON_S * +json_by_name_and_type(JSON_S *json, char *name, JObjType jtype) +{ + JSON_S *j; + + for(j = json; j ; j = j->next) + if(j->name && !compare_cstring(j->name, name)) + break; + + return j && j->value && j->value->jtype == jtype + ? (JSON_S *) (j->value->value) : NIL; +} diff --git a/imap/src/c-client/json.h b/imap/src/c-client/json.h index 88585170..75a08c38 100644 --- a/imap/src/c-client/json.h +++ b/imap/src/c-client/json.h @@ -1,5 +1,5 @@ /* - * Copyright 2018 Eduardo Chappa + * Copyright 2018-2021 Eduardo Chappa * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,21 @@ typedef struct json_s { struct json_s *next; } JSON_S; -JSON_S *json_parse(unsigned char **); +#define json_value_type(J, I, T) \ + (((jx = json_body_value((J), (I))) != NIL) \ + && jx->jtype == (T) && jx->value) \ + ? ((T) == JLong \ + ? *(long *) jx->value \ + : ((T) == JBoolean \ + ? (compare_cstring("false", (char *) jx->value) ? 1 : 0)\ + : NIL \ + ) \ + ) \ + : NIL + +void json_assign(void **, JSON_S *, char *, JObjType); +JSON_S *json_by_name_and_type(JSON_S *, char *, JObjType); +JSON_S *json_parse(unsigned char *); JSON_X *json_body_value(JSON_S *, unsigned char *); void json_free(JSON_S **); diff --git a/imap/src/c-client/oauth2_aux.c b/imap/src/c-client/oauth2_aux.c index 550f3b56..9d9fa304 100644 --- a/imap/src/c-client/oauth2_aux.c +++ b/imap/src/c-client/oauth2_aux.c @@ -114,11 +114,10 @@ JSON_S *oauth2_json_reply(OAUTH2_SERVER_METHOD_S RefreshMethod, OAUTH2_S *oauth2 if(strcmp(RefreshMethod.name, "POST") == 0 && ((stream = http_open(server)) != NULL) && ((s = http_post_param(stream, params)) != NULL)){ - unsigned char *u = s; - json = json_parse(&u); + json = json_parse(s); fs_give((void **) &s); } - *status = stream->status ? stream->status->code : -1; + *status = stream && stream->status ? stream->status->code : -1; if(stream) http_close(stream); if(server) fs_give((void **) &server); @@ -164,18 +163,9 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method, if(json != NULL){ JSON_X *jx; - jx = json_body_value(json, "device_code"); - if(jx && jx->jtype == JString) - oauth2->devicecode.device_code = cpystr((char *) jx->value); - - jx = json_body_value(json, "user_code"); - if(jx && jx->jtype == JString) - oauth2->devicecode.user_code = cpystr((char *) jx->value); - - jx = json_body_value(json, "verification_uri"); - if(jx && jx->jtype == JString) - oauth2->devicecode.verification_uri = cpystr((char *) jx->value); - + json_assign ((void **) &oauth2->devicecode.device_code, json, "device_code", JString); + json_assign ((void **) &oauth2->devicecode.user_code, json, "user_code", JString); + json_assign ((void **) &oauth2->devicecode.verification_uri, json, "verification_uri", JString); if((jx = json_body_value(json, "expires_in")) != NULL) switch(jx->jtype){ case JString: oauth2->devicecode.expires_in = atoi((char *) jx->value); @@ -194,10 +184,7 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method, default : break; } - jx = json_body_value(json, "message"); - if(jx && jx->jtype == JString) - oauth2->devicecode.message = cpystr((char *) jx->value); - + json_assign ((void **) &oauth2->devicecode.message, json, "message", JString); json_free(&json); if(oauth2->devicecode.verification_uri && oauth2->devicecode.user_code){ @@ -220,10 +207,7 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method, case HTTP_UNAUTHORIZED: mm_log("Client not authorized (wrong client-id?)", ERROR); break; - case HTTP_OK: jx = json_body_value(json, "access_token"); - if(jx && jx->jtype == JString) - oauth2->access_token = cpystr((char *) jx->value); - + case HTTP_OK: json_assign ((void **) &oauth2->access_token, json, "access_token", JString); if((jx = json_body_value(json, "expires_in")) != NULL) switch(jx->jtype){ case JString: oauth2->expiration = time(0) + atol((char *) jx->value); @@ -282,30 +266,21 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method, JSON_X *jx; switch(status){ - case HTTP_OK : jx = json_body_value(json, "refresh_token"); - if(jx && jx->jtype == JString) - oauth2->param[OA2_RefreshToken].value = cpystr((char *) jx->value); - - jx = json_body_value(json, "access_token"); - if(jx && jx->jtype == JString) - oauth2->access_token = cpystr((char *) jx->value); + case HTTP_OK : json_assign ((void **) &oauth2->param[OA2_RefreshToken].value, json, "refresh_token", JString); + json_assign ((void **) &oauth2->access_token, json, "access_token", JString); - if((jx = json_body_value(json, "expires_in")) != NULL) - switch(jx->jtype){ + if((jx = json_body_value(json, "expires_in")) != NULL) + switch(jx->jtype){ case JString: oauth2->expiration = time(0) + atol((char *) jx->value); break; case JLong : oauth2->expiration = time(0) + *(long *) jx->value; break; default : break; - } - - jx = json_body_value(json, "expires_in"); - if(jx && jx->jtype == JString) - oauth2->expiration = time(0) + atol((char *) jx->value); + } - oauth2->cancel_refresh_token = 0; /* do not cancel this token. It is good */ + oauth2->cancel_refresh_token = 0; /* do not cancel this token. It is good */ - break; + break; case HTTP_BAD : break; @@ -346,15 +321,11 @@ void oauth2deviceinfo_get_accesscode(void *inp, void *outp) if(json != NULL){ JSON_X *jx; - char *error; + char *error = NIL; switch(status){ - case HTTP_BAD : jx = json_body_value(json, "error"); - if(jx && jx->jtype == JString) - error = cpystr((char *) jx->value); - else - break; - + case HTTP_BAD : json_assign ((void **) &error, json, "error", JString); + if(!error) break; if(compare_cstring(error, "authorization_pending") == 0) rv = OA2_CODE_WAIT; else if(compare_cstring(error, "authorization_declined") == 0) @@ -368,13 +339,8 @@ void oauth2deviceinfo_get_accesscode(void *inp, void *outp) break; - case HTTP_OK : jx = json_body_value(json, "refresh_token"); - if(jx && jx->jtype == JString) - oauth2->param[OA2_RefreshToken].value = cpystr((char *) jx->value); - - jx = json_body_value(json, "access_token"); - if(jx && jx->jtype == JString) - oauth2->access_token = cpystr((char *) jx->value); + case HTTP_OK : json_assign ((void **) &oauth2->param[OA2_RefreshToken].value, json, "refresh_token", JString); + json_assign ((void **) &oauth2->access_token, json, "access_token", JString); if((jx = json_body_value(json, "expires_in")) != NULL) switch(jx->jtype){ |