cgmnlm

colorful gemini line mode browser
git clone https://git.clttr.info/cgmnlm.git
Log (Feed) | Files | Refs (Tags) | README | LICENSE

commit 95518992983e6531106b48c82edeb0ce825bf351
parent 02c2be62daceb04e4891d415c997dd64db84b9d9
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun, 20 Sep 2020 16:32:01 -0400

Add response status enum

Diffstat:
Dinclude/client.h | 71-----------------------------------------------------------------------
Ainclude/gmni.h | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/client.c | 8+++++++-
Msrc/gmni.c | 16++++++++--------
4 files changed, 120 insertions(+), 80 deletions(-)

diff --git a/include/client.h b/include/client.h @@ -1,71 +0,0 @@ -#ifndef GEMINI_CLIENT_H -#define GEMINI_CLIENT_H -#include <netdb.h> -#include <openssl/ssl.h> -#include <sys/socket.h> - -struct gemini_response { - int status; - char *meta; - - // Response body may be read from here if appropriate: - BIO *bio; - - // Connection state - SSL_CTX *ssl_ctx; - SSL *ssl; - int fd; -}; - -struct gemini_options { - // If NULL, an SSL context will be created. If unset, the ssl field - // must also be NULL. - SSL_CTX *ssl_ctx; - - // If NULL, an SSL connection will be established. If set, it is - // presumed that the caller pre-established the SSL connection. - SSL *ssl; - - // If ai_family != AF_UNSPEC (the default value on most systems), the - // client will connect to this address and skip name resolution. - struct addrinfo *addr; - - // If non-NULL, these hints are provided to getaddrinfo. Useful, for - // example, to force IPv4/IPv6. - struct addrinfo *hints; -}; - -enum gemini_result { - GEMINI_OK, - GEMINI_ERR_OOM, - GEMINI_ERR_INVALID_URL, - GEMINI_ERR_RESOLVE, - GEMINI_ERR_CONNECT, - GEMINI_ERR_SSL, - GEMINI_ERR_IO, - GEMINI_ERR_PROTOCOL, -}; - -// Requests the specified URL via the gemini protocol. If options is non-NULL, -// it may specify some additional configuration to adjust client behavior. -// -// Returns a value indicating the success of the request. -// -// Caller must call gemini_response_finish afterwards to clean up resources -// before exiting or re-using it for another request. -enum gemini_result gemini_request(const char *url, - struct gemini_options *options, - struct gemini_response *resp); - -// Must be called after gemini_request in order to free up the resources -// allocated during the request. -void gemini_response_finish(struct gemini_response *resp); - -// Returns a user-friendly string describing an error. -const char *gemini_strerr(enum gemini_result r, struct gemini_response *resp); - -// Returns the given URL with the input response set to the specified value. -// The caller must free the string. -char *gemini_input_url(const char *url, const char *input); - -#endif diff --git a/include/gmni.h b/include/gmni.h @@ -0,0 +1,105 @@ +#ifndef GEMINI_CLIENT_H +#define GEMINI_CLIENT_H +#include <netdb.h> +#include <openssl/ssl.h> +#include <sys/socket.h> + +enum gemini_result { + GEMINI_OK, + GEMINI_ERR_OOM, + GEMINI_ERR_INVALID_URL, + GEMINI_ERR_RESOLVE, + GEMINI_ERR_CONNECT, + GEMINI_ERR_SSL, + GEMINI_ERR_IO, + GEMINI_ERR_PROTOCOL, +}; + +enum gemini_status { + GEMINI_STATUS_INPUT = 10, + GEMINI_STATUS_SENSITIVE_INPUT = 11, + GEMINI_STATUS_SUCCESS = 20, + GEMINI_STATUS_REDIRECT_TEMPORARY = 30, + GEMINI_STATUS_REDIRECT_PERMANENT = 31, + GEMINI_STATUS_TEMPORARY_FAILURE = 40, + GEMINI_STATUS_SERVER_UNAVAILABLE = 41, + GEMINI_STATUS_CGI_ERROR = 42, + GEMINI_STATUS_PROXY_ERROR = 43, + GEMINI_STATUS_SLOW_DOWN = 44, + GEMINI_STATUS_PERMANENT_FAILURE = 50, + GEMINI_STATUS_NOT_FOUND = 51, + GEMINI_STATUS_GONE = 52, + GEMINI_STATUS_PROXY_REQUEST_REFUSED = 53, + GEMINI_STATUS_BAD_REQUEST = 59, + GEMINI_STATUS_CLIENT_CERTIFICATE_REQUIRED = 60, + GEMINI_STATUS_CERTIFICATE_NOT_AUTHORIZED = 61, + GEMINI_STATUS_CERTIFICATE_NOT_VALID = 62, +}; + +enum gemini_status_class { + GEMINI_STATUS_CLASS_INPUT = 10, + GEMINI_STATUS_CLASS_SUCCESS = 20, + GEMINI_STATUS_CLASS_REDIRECT = 30, + GEMINI_STATUS_CLASS_TEMPORARY_FAILURE = 40, + GEMINI_STATUS_CLASS_PERMANENT_FAILURE = 50, + GEMINI_STATUS_CLASS_CLIENT_CERTIFICATE_REQUIRED = 60, +}; + +struct gemini_response { + enum gemini_status status; + char *meta; + + // Response body may be read from here if appropriate: + BIO *bio; + + // Connection state + SSL_CTX *ssl_ctx; + SSL *ssl; + int fd; +}; + +struct gemini_options { + // If NULL, an SSL context will be created. If unset, the ssl field + // must also be NULL. + SSL_CTX *ssl_ctx; + + // If NULL, an SSL connection will be established. If set, it is + // presumed that the caller pre-established the SSL connection. + SSL *ssl; + + // If ai_family != AF_UNSPEC (the default value on most systems), the + // client will connect to this address and skip name resolution. + struct addrinfo *addr; + + // If non-NULL, these hints are provided to getaddrinfo. Useful, for + // example, to force IPv4/IPv6. + struct addrinfo *hints; +}; + +// Requests the specified URL via the gemini protocol. If options is non-NULL, +// it may specify some additional configuration to adjust client behavior. +// +// Returns a value indicating the success of the request. +// +// Caller must call gemini_response_finish afterwards to clean up resources +// before exiting or re-using it for another request. +enum gemini_result gemini_request(const char *url, + struct gemini_options *options, + struct gemini_response *resp); + +// Must be called after gemini_request in order to free up the resources +// allocated during the request. +void gemini_response_finish(struct gemini_response *resp); + +// Returns a user-friendly string describing an error. +const char *gemini_strerr(enum gemini_result r, struct gemini_response *resp); + +// Returns the given URL with the input response set to the specified value. +// The caller must free the string. +char *gemini_input_url(const char *url, const char *input); + +// Returns the general response class (i.e. with the second digit set to zero) +// of the given Gemini status code. +enum gemini_status_class gemini_response_class(enum gemini_status status); + +#endif diff --git a/src/client.c b/src/client.c @@ -9,7 +9,7 @@ #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> -#include "client.h" +#include "gmni.h" #include "url.h" static enum gemini_result @@ -264,3 +264,9 @@ cleanup: curl_url_cleanup(uri); return new_url; } + +enum gemini_status_class +gemini_response_class(enum gemini_status status) +{ + return status / 10; +} diff --git a/src/gmni.c b/src/gmni.c @@ -11,7 +11,7 @@ #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> -#include "client.h" +#include "gmni.h" static void usage(char *argv_0) @@ -120,8 +120,8 @@ main(int argc, char *argv[]) } char *new_url, *input = NULL; - switch (resp.status / 10) { - case 1: // INPUT + switch (gemini_response_class(resp.status)) { + case GEMINI_STATUS_CLASS_INPUT: if (input_mode == INPUT_SUPPRESS) { exit = true; break; @@ -149,7 +149,7 @@ main(int argc, char *argv[]) url = new_url; assert(url); goto next; - case 3: // REDIRECT + case GEMINI_STATUS_CLASS_REDIRECT: free(url); url = strdup(resp.meta); if (!follow_redirects) { @@ -160,10 +160,10 @@ main(int argc, char *argv[]) exit = true; } goto next; - case 6: // CLIENT CERTIFICATE REQUIRED + case GEMINI_STATUS_CLASS_CLIENT_CERTIFICATE_REQUIRED: assert(0); // TODO - case 4: // TEMPORARY FAILURE - case 5: // PERMANENT FAILURE + case GEMINI_STATUS_CLASS_TEMPORARY_FAILURE: + case GEMINI_STATUS_CLASS_PERMANENT_FAILURE: if (header_mode == OMIT_HEADERS) { fprintf(stderr, "%s: %d %s\n", resp.status / 10 == 4 ? @@ -172,7 +172,7 @@ main(int argc, char *argv[]) } exit = true; break; - case 2: // SUCCESS + case GEMINI_STATUS_CLASS_SUCCESS: exit = true; break; }