commit 95518992983e6531106b48c82edeb0ce825bf351
parent 02c2be62daceb04e4891d415c997dd64db84b9d9
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 20 Sep 2020 16:32:01 -0400
Add response status enum
Diffstat:
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;
}