diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-07-16 22:55:07 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-07-16 22:55:07 +0300 |
commit | 0d9c3c4cb9bc9571cd3c38446c720f93e36cc8ad (patch) | |
tree | 7787e4433b49b8196cf8725bb27a2c9eb41a6fbb /src/gmrequest.c | |
parent | b89dc234998b75c67cf3cd080102f623519496c8 (diff) |
GmRequest: Support for Titan payloads
Diffstat (limited to 'src/gmrequest.c')
-rw-r--r-- | src/gmrequest.c | 91 |
1 files changed, 80 insertions, 11 deletions
diff --git a/src/gmrequest.c b/src/gmrequest.c index 44ef063f..1d84ef47 100644 --- a/src/gmrequest.c +++ b/src/gmrequest.c | |||
@@ -118,6 +118,31 @@ void deserialize_GmResponse(iGmResponse *d, iStream *ins) { | |||
118 | 118 | ||
119 | /*----------------------------------------------------------------------------------------------*/ | 119 | /*----------------------------------------------------------------------------------------------*/ |
120 | 120 | ||
121 | iDeclareType(TitanData) | ||
122 | iDeclareTypeConstruction(TitanData) | ||
123 | |||
124 | struct Impl_TitanData { | ||
125 | iBlock data; | ||
126 | iString mime; | ||
127 | iString token; | ||
128 | }; | ||
129 | |||
130 | iDefineTypeConstruction(TitanData) | ||
131 | |||
132 | void init_TitanData(iTitanData *d) { | ||
133 | init_Block(&d->data, 0); | ||
134 | init_String(&d->mime); | ||
135 | init_String(&d->token); | ||
136 | } | ||
137 | |||
138 | void deinit_TitanData(iTitanData *d) { | ||
139 | deinit_String(&d->token); | ||
140 | deinit_String(&d->mime); | ||
141 | deinit_Block(&d->data); | ||
142 | } | ||
143 | |||
144 | /*----------------------------------------------------------------------------------------------*/ | ||
145 | |||
121 | static iAtomicInt idGen_; | 146 | static iAtomicInt idGen_; |
122 | 147 | ||
123 | enum iGmRequestState { | 148 | enum iGmRequestState { |
@@ -135,6 +160,7 @@ struct Impl_GmRequest { | |||
135 | iGmCerts * certs; /* not owned */ | 160 | iGmCerts * certs; /* not owned */ |
136 | enum iGmRequestState state; | 161 | enum iGmRequestState state; |
137 | iString url; | 162 | iString url; |
163 | iTitanData * titan; | ||
138 | iTlsRequest * req; | 164 | iTlsRequest * req; |
139 | iGopher gopher; | 165 | iGopher gopher; |
140 | iGmResponse * resp; | 166 | iGmResponse * resp; |
@@ -498,20 +524,21 @@ static void beginGopherConnection_GmRequest_(iGmRequest *d, const iString *host, | |||
498 | /*----------------------------------------------------------------------------------------------*/ | 524 | /*----------------------------------------------------------------------------------------------*/ |
499 | 525 | ||
500 | void init_GmRequest(iGmRequest *d, iGmCerts *certs) { | 526 | void init_GmRequest(iGmRequest *d, iGmCerts *certs) { |
501 | d->mtx = new_Mutex(); | 527 | d->mtx = new_Mutex(); |
502 | d->id = add_Atomic(&idGen_, 1) + 1; | 528 | d->id = add_Atomic(&idGen_, 1) + 1; |
503 | d->resp = new_GmResponse(); | 529 | d->resp = new_GmResponse(); |
504 | d->isFilterEnabled = iTrue; | 530 | d->isFilterEnabled = iTrue; |
505 | d->isRespLocked = iFalse; | 531 | d->isRespLocked = iFalse; |
506 | d->isRespFiltered = iFalse; | 532 | d->isRespFiltered = iFalse; |
507 | set_Atomic(&d->allowUpdate, iTrue); | 533 | set_Atomic(&d->allowUpdate, iTrue); |
508 | init_String(&d->url); | 534 | init_String(&d->url); |
509 | init_Gopher(&d->gopher); | 535 | init_Gopher(&d->gopher); |
510 | d->certs = certs; | 536 | d->titan = NULL; |
511 | d->req = NULL; | 537 | d->certs = certs; |
512 | d->updated = NULL; | 538 | d->req = NULL; |
513 | d->finished = NULL; | 539 | d->updated = NULL; |
514 | d->state = initialized_GmRequestState; | 540 | d->finished = NULL; |
541 | d->state = initialized_GmRequestState; | ||
515 | } | 542 | } |
516 | 543 | ||
517 | void deinit_GmRequest(iGmRequest *d) { | 544 | void deinit_GmRequest(iGmRequest *d) { |
@@ -529,6 +556,7 @@ void deinit_GmRequest(iGmRequest *d) { | |||
529 | unlock_Mutex(d->mtx); | 556 | unlock_Mutex(d->mtx); |
530 | } | 557 | } |
531 | iReleasePtr(&d->req); | 558 | iReleasePtr(&d->req); |
559 | delete_TitanData(d->titan); | ||
532 | deinit_Gopher(&d->gopher); | 560 | deinit_Gopher(&d->gopher); |
533 | delete_Audience(d->finished); | 561 | delete_Audience(d->finished); |
534 | delete_Audience(d->updated); | 562 | delete_Audience(d->updated); |
@@ -553,6 +581,20 @@ void setUrl_GmRequest(iGmRequest *d, const iString *url) { | |||
553 | urlEncodeSpaces_String(&d->url); | 581 | urlEncodeSpaces_String(&d->url); |
554 | } | 582 | } |
555 | 583 | ||
584 | static iBool isTitan_GmRequest_(const iGmRequest *d) { | ||
585 | return equalCase_Rangecc(urlScheme_String(&d->url), "titan"); | ||
586 | } | ||
587 | |||
588 | void setTitanData_GmRequest(iGmRequest *d, const iString *mime, const iBlock *payload, | ||
589 | const iString *token) { | ||
590 | if (!d->titan) { | ||
591 | d->titan = new_TitanData(); | ||
592 | } | ||
593 | set_Block(&d->titan->data, payload); | ||
594 | set_String(&d->titan->mime, mime); | ||
595 | set_String(&d->titan->token, token); | ||
596 | } | ||
597 | |||
556 | static iBool isDirectory_(const iString *path) { | 598 | static iBool isDirectory_(const iString *path) { |
557 | /* TODO: move this to the_Foundation */ | 599 | /* TODO: move this to the_Foundation */ |
558 | iFileInfo *info = new_FileInfo(path); | 600 | iFileInfo *info = new_FileInfo(path); |
@@ -837,7 +879,8 @@ void submit_GmRequest(iGmRequest *d) { | |||
837 | beginGopherConnection_GmRequest_(d, host, port ? port : 79); | 879 | beginGopherConnection_GmRequest_(d, host, port ? port : 79); |
838 | return; | 880 | return; |
839 | } | 881 | } |
840 | else if (!equalCase_Rangecc(url.scheme, "gemini")) { | 882 | else if (!equalCase_Rangecc(url.scheme, "gemini") && |
883 | !equalCase_Rangecc(url.scheme, "titan")) { | ||
841 | resp->statusCode = unsupportedProtocol_GmStatusCode; | 884 | resp->statusCode = unsupportedProtocol_GmStatusCode; |
842 | d->state = finished_GmRequestState; | 885 | d->state = finished_GmRequestState; |
843 | iNotifyAudience(d, finished, GmRequestFinished); | 886 | iNotifyAudience(d, finished, GmRequestFinished); |
@@ -855,8 +898,34 @@ void submit_GmRequest(iGmRequest *d) { | |||
855 | port = GEMINI_DEFAULT_PORT; /* default Gemini port */ | 898 | port = GEMINI_DEFAULT_PORT; /* default Gemini port */ |
856 | } | 899 | } |
857 | setHost_TlsRequest(d->req, host, port); | 900 | setHost_TlsRequest(d->req, host, port); |
858 | setContent_TlsRequest(d->req, | 901 | /* Titan requests can have an arbitrary payload. */ |
859 | utf8_String(collectNewFormat_String("%s\r\n", cstr_String(&d->url)))); | 902 | if (isTitan_GmRequest_(d)) { |
903 | iBlock content; | ||
904 | initCopy_Block(&content, utf8_String(&d->url)); | ||
905 | if (d->titan) { | ||
906 | printf_Block(&content, | ||
907 | ";mime=%s;size=%zu", | ||
908 | cstr_String(&d->titan->mime), | ||
909 | size_Block(&d->titan->data)); | ||
910 | if (!isEmpty_String(&d->titan->token)) { | ||
911 | appendCStr_Block(&content, ";token="); | ||
912 | append_Block(&content, utf8_String(&d->titan->token)); | ||
913 | } | ||
914 | appendCStr_Block(&content, "\r\n"); | ||
915 | append_Block(&content, &d->titan->data); | ||
916 | } | ||
917 | else { | ||
918 | /* Empty data. */ | ||
919 | appendCStr_Block(&content, ";mime=application/octet-stream;size=0\r\n"); | ||
920 | } | ||
921 | setContent_TlsRequest(d->req, &content); | ||
922 | deinit_Block(&content); | ||
923 | } | ||
924 | else { | ||
925 | /* Gemini request. */ | ||
926 | setContent_TlsRequest(d->req, | ||
927 | utf8_String(collectNewFormat_String("%s\r\n", cstr_String(&d->url)))); | ||
928 | } | ||
860 | submit_TlsRequest(d->req); | 929 | submit_TlsRequest(d->req); |
861 | } | 930 | } |
862 | 931 | ||