Merge branch 'nate-i50189-http-context' into 'master'
See merge request SchedMD/dev/slurm!1949
diff --git a/src/common/http.c b/src/common/http.c
index 73e03c8..cd68e92 100644
--- a/src/common/http.c
+++ b/src/common/http.c
@@ -411,3 +411,50 @@
dst->query = xstrdup(src->query);
dst->fragment = xstrdup(src->fragment);
}
+
+extern void free_http_header(http_header_t *header)
+{
+ xassert(header->magic == HTTP_HEADER_MAGIC);
+ xfree(header->name);
+ xfree(header->value);
+ header->magic = ~HTTP_HEADER_MAGIC;
+ xfree(header);
+}
+
+/* find operator against http_header_t */
+static int _http_header_find_key(void *x, void *y)
+{
+ const http_header_t *entry = x;
+ const char *key = y;
+
+ xassert(entry->name);
+ xassert(entry->magic == HTTP_HEADER_MAGIC);
+
+ if (key == NULL)
+ return 0;
+
+ /* case insensitive compare per rfc2616:4.2 */
+ if (entry->name && !xstrcasecmp(entry->name, key))
+ return 1;
+ else
+ return 0;
+}
+
+extern const char *find_http_header(list_t *headers, const char *name)
+{
+ http_header_t *header = NULL;
+
+ if (!headers || !name)
+ return NULL;
+
+ header = (http_header_t *) list_find_first(headers,
+ _http_header_find_key,
+ (void *) name);
+
+ if (header) {
+ xassert(header->magic == HTTP_HEADER_MAGIC);
+ return header->value;
+ }
+
+ return NULL;
+}
diff --git a/src/common/http.h b/src/common/http.h
index 8705a2a..1d2aa4b 100644
--- a/src/common/http.h
+++ b/src/common/http.h
@@ -209,4 +209,23 @@
/* Copy all members in URL */
extern void url_copy_members(url_t *dst, const url_t *src);
+#define HTTP_HEADER_MAGIC 0x1aaffbe2
+
+/* HTTP header */
+typedef struct {
+ int magic; /* HTTP_HEADER_MAGIC */
+ char *name;
+ char *value;
+} http_header_t;
+
+/* Free http header and contents */
+extern void free_http_header(http_header_t *header);
+
+/* find http header from header list
+ * IN headers - list_t of http_header_t*
+ * IN name - name of header to find
+ * RET ptr to header value or NULL if not found
+ */
+extern const char *find_http_header(list_t *headers, const char *name);
+
#endif /* SLURM_HTTP_H */
diff --git a/src/conmgr/con.c b/src/conmgr/con.c
index fdaaa44..c06f301 100644
--- a/src/conmgr/con.c
+++ b/src/conmgr/con.c
@@ -1931,8 +1931,7 @@
xassert(con->refs >= 0);
ref->magic = ~MAGIC_CON_MGR_FD_REF;
- xfree(ref);
- *ref_ptr = NULL;
+ xfree((*ref_ptr));
}
extern void conmgr_fd_free_ref(conmgr_fd_ref_t **ref_ptr)
diff --git a/src/conmgr/conmgr.h b/src/conmgr/conmgr.h
index abd7549..a582b46 100644
--- a/src/conmgr/conmgr.h
+++ b/src/conmgr/conmgr.h
@@ -426,7 +426,7 @@
extern int conmgr_queue_send_fd(conmgr_fd_t *con, int fd);
/*
- * Write binary data to connection (from callback).
+ * Write binary data to connection
* NOTE: type=CON_TYPE_RAW only
* IN con connection manager connection struct
* IN buffer pointer to buffer
@@ -437,6 +437,17 @@
const size_t bytes);
/*
+ * Copy and write binary data to connection
+ * NOTE: type=CON_TYPE_RAW only
+ * IN ref reference to connection
+ * IN buffer pointer to buffer
+ * IN bytes number of bytes in buffer to write
+ * RET SLURM_SUCCESS or error
+ */
+extern int conmgr_con_queue_write_data(conmgr_fd_ref_t *ref, const void *buffer,
+ const size_t bytes);
+
+/*
* Write packed msg to connection (from callback).
* NOTE: type=CON_TYPE_RPC only
* IN con conmgr connection ptr
diff --git a/src/conmgr/io.c b/src/conmgr/io.c
index ba0bcd6..890d914 100644
--- a/src/conmgr/io.c
+++ b/src/conmgr/io.c
@@ -422,24 +422,33 @@
con->in->size = size;
}
-extern int conmgr_queue_write_data(conmgr_fd_t *con, const void *buffer,
- const size_t bytes)
+/* Copy buffer into new buf_t */
+static buf_t *_buf_clone(const void *buffer, const size_t bytes)
{
- buf_t *buf;
+ buf_t *buf = NULL;
- xassert(con->magic == MAGIC_CON_MGR_FD);
-
- /* Ignore empty write requests */
- if (!bytes)
- return SLURM_SUCCESS;
+ xassert(bytes > 0);
buf = init_buf(bytes);
- /* TODO: would be nice to avoid this copy */
memmove(get_buf_data(buf), buffer, bytes);
- log_flag(NET, "%s: [%s] write of %zu bytes queued",
- __func__, con->name, bytes);
+ return buf;
+}
+
+/*
+ * Append buffer to output queue
+ * WARNING: caller must hold mgr.mutex lock
+ * IN con - connection to queue outgoing buffer
+ * IN buf - buffer to queue as output (takes ownership)
+ * RET SLURM_SUCCESS or error
+ */
+static int _append_output(conmgr_fd_t *con, buf_t *buf)
+{
+ xassert(con->magic == MAGIC_CON_MGR_FD);
+
+ log_flag(NET, "%s: [%s] write of %u bytes queued",
+ __func__, con->name, get_buf_offset(buf));
log_flag_hex(NET_RAW, get_buf_data(buf), get_buf_offset(buf),
"%s: queuing up write", __func__);
@@ -449,12 +458,54 @@
if (con_flag(con, FLAG_WATCH_WRITE_TIMEOUT))
con->last_write = timespec_now();
- slurm_mutex_lock(&mgr.mutex);
EVENT_SIGNAL(&mgr.watch_sleep);
- slurm_mutex_unlock(&mgr.mutex);
+
return SLURM_SUCCESS;
}
+static int _write_data(conmgr_fd_t *con, const void *buffer, const size_t bytes)
+{
+ int rc = EINVAL;
+ buf_t *buf = NULL;
+
+ xassert(con->magic == MAGIC_CON_MGR_FD);
+
+ /* Ignore empty write requests */
+ if (!bytes)
+ return SLURM_SUCCESS;
+
+ /* TODO: would be nice to avoid this copy */
+ buf = _buf_clone(buffer, bytes);
+
+ slurm_mutex_lock(&mgr.mutex);
+ rc = _append_output(con, buf);
+ slurm_mutex_unlock(&mgr.mutex);
+
+ return rc;
+}
+
+extern int conmgr_queue_write_data(conmgr_fd_t *con, const void *buffer,
+ const size_t bytes)
+{
+ xassert(con->magic == MAGIC_CON_MGR_FD);
+ xassert(buffer || !bytes);
+
+ return _write_data(con, buffer, bytes);
+}
+
+extern int conmgr_con_queue_write_data(conmgr_fd_ref_t *ref, const void *buffer,
+ const size_t bytes)
+{
+ if (!ref)
+ return EINVAL;
+
+ xassert(ref->magic == MAGIC_CON_MGR_FD_REF);
+ xassert(ref->con->magic == MAGIC_CON_MGR_FD);
+ xassert(buffer || !bytes);
+
+ return _write_data(ref->con, buffer, bytes);
+}
+
static int _get_input_buffer(const conmgr_fd_t *con, const void **data_ptr,
size_t *bytes_ptr)
{
diff --git a/src/slurmrestd/http.c b/src/slurmrestd/http.c
index 666dc3a..e4915f4 100644
--- a/src/slurmrestd/http.c
+++ b/src/slurmrestd/http.c
@@ -50,6 +50,8 @@
#include "src/common/xmalloc.h"
#include "src/common/xstring.h"
+#include "src/conmgr/conmgr.h"
+
#include "src/interfaces/http_parser.h"
#include "src/slurmrestd/http.h"
@@ -59,10 +61,8 @@
#define MAGIC 0xDFAFFEEF
#define MAX_BODY_BYTES 52428800 /* 50MB */
-#define MAGIC_REQUEST_T 0xdbadaaaf
/* Data to handed around by http_parser to call backs */
typedef struct {
- int magic;
/* Requested URL */
url_t url;
/* Request HTTP method */
@@ -76,8 +76,6 @@
/* RFC7230-6.1 "Connection: Close" */
bool connection_close;
int expect; /* RFC7231-5.1.1 expect requested */
- /* Connection context */
- http_context_t *context;
/* Body of request (may be NULL) */
char *body;
/* if provided: expected body length to process or 0 */
@@ -93,6 +91,22 @@
} http_version;
} request_t;
+typedef struct http_context_s {
+ int magic; /* MAGIC */
+ /* reference to assigned connection */
+ conmgr_fd_ref_t *ref;
+ /* assigned connection */
+ conmgr_fd_t *con;
+ /* Authentication context (auth_context_type_t) */
+ void *auth;
+ /* callback to call on each HTTP request */
+ on_http_request_t on_http_request;
+ /* http parser plugin state */
+ http_parser_state_t *parser;
+ /* http request_t */
+ request_t request;
+} http_context_t;
+
/* default keep_alive value which appears to be implementation specific */
static int DEFAULT_KEEP_ALIVE = 5; //default to 5s to match apache2
@@ -110,13 +124,6 @@
return ESLURM_HTTP_UNSUPPORTED_VERSION;
}
-extern void free_http_header(http_header_entry_t *header)
-{
- xfree(header->name);
- xfree(header->value);
- xfree(header);
-}
-
static void _free_http_header(void *header)
{
free_http_header(header);
@@ -124,16 +131,14 @@
static void _request_init(http_context_t *context)
{
- request_t *request = context->request;
+ request_t *request = &context->request;
xassert(request);
xassert(context->magic == MAGIC);
*request = (request_t) {
- .magic = MAGIC_REQUEST_T,
.url = URL_INITIALIZER,
.method = HTTP_REQUEST_INVALID,
- .context = context,
.keep_alive = -1,
};
@@ -142,11 +147,9 @@
static void _request_free_members(http_context_t *context)
{
- request_t *request = context->request;
+ request_t *request = &context->request;
xassert(context->magic == MAGIC);
- xassert(request->magic == MAGIC_REQUEST_T);
- xassert(request->context == context);
url_free_members(&request->url);
FREE_NULL_LIST(request->headers);
@@ -170,12 +173,11 @@
static int _on_request(const http_parser_request_t *req, void *arg)
{
- request_t *request = arg;
- http_context_t *context = request->context;
+ http_context_t *context = arg;
+ request_t *request = &context->request;
int rc = EINVAL;
xassert(context->magic == MAGIC);
- xassert(request->magic == MAGIC_REQUEST_T);
request->http_version.major = req->http_version.major;
request->http_version.minor = req->http_version.minor;
@@ -228,12 +230,11 @@
static int _on_header(const http_parser_header_t *header, void *arg)
{
- request_t *request = arg;
- http_context_t *context = request->context;
- http_header_entry_t *entry = NULL;
+ http_context_t *context = arg;
+ request_t *request = &context->request;
+ http_header_t *entry = NULL;
xassert(context->magic == MAGIC);
- xassert(request->magic == MAGIC_REQUEST_T);
log_flag(NET, "%s: [%s] Header: %s Value: %s",
__func__, conmgr_con_get_name(context->ref), header->name,
@@ -241,6 +242,7 @@
/* Add copy to list of headers */
entry = xmalloc(sizeof(*entry));
+ entry->magic = HTTP_HEADER_MAGIC;
entry->name = xstrdup(header->name);
entry->value = xstrdup(header->value);
list_append(request->headers, entry);
@@ -264,8 +266,7 @@
request->keep_alive = ibuffer;
} else {
error("%s: [%s] invalid Keep-Alive value %s",
- __func__,
- conmgr_fd_get_name(request->context->con),
+ __func__, conmgr_con_get_name(context->ref),
header->value);
return _send_reject(
context, HTTP_STATUS_CODE_ERROR_NOT_ACCEPTABLE,
@@ -319,11 +320,10 @@
static int _on_headers_complete(void *arg)
{
- request_t *request = arg;
- http_context_t *context = request->context;
+ http_context_t *context = arg;
+ request_t *request = &context->request;
xassert(context->magic == MAGIC);
- xassert(request->magic == MAGIC_REQUEST_T);
if ((request->http_version.major == 1) &&
(request->http_version.minor == 0)) {
@@ -355,13 +355,14 @@
if (request->expect) {
int rc = EINVAL;
send_http_response_args_t args = {
- .con = context->con,
.http_major = request->http_version.major,
.http_minor = request->http_version.minor,
.status_code = request->expect,
.body_length = 0,
};
+ args.con = conmgr_fd_get_ref(context->ref);
+
if ((rc = send_http_response(&args)))
return rc;
}
@@ -371,13 +372,12 @@
static int _on_content(const http_parser_content_t *content, void *arg)
{
- request_t *request = arg;
- http_context_t *context = request->context;
+ http_context_t *context = arg;
+ request_t *request = &context->request;
const void *at = get_buf_data(content->buffer);
const size_t length = get_buf_offset(content->buffer);
xassert(context->magic == MAGIC);
- xassert(request->magic == MAGIC_REQUEST_T);
log_flag_hex(NET_RAW, at, length, "%s: [%s] received HTTP content",
__func__, conmgr_con_get_name(context->ref));
@@ -456,7 +456,7 @@
static int _write_fmt_header(conmgr_fd_t *con, const char *name,
const char *value)
{
- const char *buffer = _fmt_header(name, value);
+ char *buffer = _fmt_header(name, value);
int rc = conmgr_queue_write_data(con, buffer, strlen(buffer));
xfree(buffer);
return rc;
@@ -474,7 +474,13 @@
return xstrdup_printf("%s: %zu" CRLF, name, value);
}
-extern int send_http_connection_close(http_context_t *ctxt)
+/*
+ * Send HTTP close notification header
+ * Warns the client that we are about to close the connection.
+ * IN ctxt - connection context
+ * RET SLURM_SUCCESS or error
+ */
+static int _send_http_connection_close(http_context_t *ctxt)
{
return _write_fmt_header(ctxt->con, "Connection", "Close");
}
@@ -520,8 +526,9 @@
/* send along any requested headers */
if (args->headers) {
list_itr_t *itr = list_iterator_create(args->headers);
- http_header_entry_t *header = NULL;
+ http_header_t *header = NULL;
while ((header = list_next(itr))) {
+ xassert(header->magic == HTTP_HEADER_MAGIC);
if ((rc = _write_fmt_header(args->con, header->name,
header->value)))
break;
@@ -578,10 +585,8 @@
static int _send_reject(http_context_t *context, http_status_code_t status_code,
slurm_err_t error_number)
{
- request_t *request = context->request;
- xassert(request->magic == MAGIC_REQUEST_T);
+ request_t *request = &context->request;
send_http_response_args_t args = {
- .con = request->context->con,
.http_major = request->http_version.major,
.http_minor = request->http_version.minor,
.status_code = status_code,
@@ -591,6 +596,8 @@
xassert(context->magic == MAGIC);
+ args.con = conmgr_fd_get_ref(context->ref);
+
/* If we don't have a requested client version, default to 0.9 */
if ((args.http_major == 0) && (args.http_minor == 0))
args.http_minor = 9;
@@ -602,10 +609,11 @@
if (request->connection_close ||
_valid_http_version(request->http_version.major,
request->http_version.minor))
- send_http_connection_close(request->context);
+ _send_http_connection_close(context);
/* ensure connection gets closed */
- (void) conmgr_queue_close_fd(request->context->con);
+ conmgr_con_queue_close_free(&context->ref);
+ context->con = NULL;
/* reset connection to avoid any possible auth inheritance */
_request_reset(context);
@@ -613,10 +621,10 @@
return error_number;
}
-static int _on_message_complete_request(request_t *request)
+static int _on_message_complete_request(http_context_t *context)
{
int rc = EINVAL;
- http_context_t *context = request->context;
+ request_t *request = &context->request;
on_http_request_args_t args = {
.method = request->method,
.headers = request->headers,
@@ -633,24 +641,28 @@
};
xassert(context->magic == MAGIC);
- xassert(request->magic == MAGIC_REQUEST_T);
- if ((rc = context->on_http_request(&args)))
+ if (!(args.con = conmgr_con_link(context->ref)) ||
+ !(args.name = conmgr_con_get_name(args.con))) {
+ rc = SLURM_COMMUNICATIONS_MISSING_SOCKET_ERROR;
+ log_flag(NET, "%s: connection missing: %s",
+ __func__, slurm_strerror(rc));
+ } else if ((rc = context->on_http_request(&args)))
log_flag(NET, "%s: [%s] on_http_request rejected: %s",
__func__, conmgr_con_get_name(context->ref),
slurm_strerror(rc));
+ conmgr_fd_free_ref(&args.con);
return rc;
}
static int _on_content_complete(void *arg)
{
- request_t *request = arg;
- http_context_t *context = request->context;
+ http_context_t *context = arg;
+ request_t *request = &context->request;
int rc = EINVAL;
xassert(context->magic == MAGIC);
- xassert(request->magic == MAGIC_REQUEST_T);
if ((request->expected_body_length > 0) &&
(request->expected_body_length != request->body_length)) {
@@ -661,7 +673,7 @@
ESLURM_HTTP_INVALID_CONTENT_LENGTH);
}
- if ((rc = _on_message_complete_request(request)))
+ if ((rc = _on_message_complete_request(context)))
return rc;
if (request->keep_alive) {
@@ -673,7 +685,7 @@
if (request->connection_close) {
/* Notify client that this connection will be closed now */
if (request->connection_close)
- send_http_connection_close(context);
+ _send_http_connection_close(context);
conmgr_con_queue_close_free(&context->ref);
context->con = NULL;
@@ -695,19 +707,15 @@
.on_content_complete = _on_content_complete,
};
int rc = SLURM_SUCCESS;
- request_t *request = context->request;
ssize_t bytes_parsed = -1;
buf_t *buffer = NULL;
xassert(context->magic == MAGIC);
- xassert(context->con);
- xassert(context->ref);
- xassert(request->magic == MAGIC_REQUEST_T);
- xassert(request->context == context);
+ xassert(conmgr_fd_get_ref(context->ref) == context->con);
if (!context->parser &&
(rc = http_parser_g_new_parse_request(
- conmgr_con_get_name(context->ref), &callbacks, request,
+ conmgr_con_get_name(context->ref), &callbacks, context,
&context->parser))) {
log_flag(NET, "%s: [%s] Creating new HTTP parser failed: %s",
__func__, conmgr_con_get_name(context->ref),
@@ -754,59 +762,16 @@
return rc;
}
-static http_context_t *_http_context_new(void)
-{
- http_context_t *context = xmalloc(sizeof(*context));
- context->magic = MAGIC;
- return context;
-}
-
-/* find operator against http_header_entry_t */
-static int _http_header_find_key(void *x, void *y)
-{
- http_header_entry_t *entry = (http_header_entry_t *)x;
- const char *key = (const char *)y;
- xassert(entry->name);
-
- if (key == NULL)
- return 0;
- /* case insensitive compare per rfc2616:4.2 */
- if (entry->name && !xstrcasecmp(entry->name, key))
- return 1;
- else
- return 0;
-}
-
-extern const char *find_http_header(list_t *headers, const char *name)
-{
- http_header_entry_t *header = NULL;
-
- if (!headers || !name)
- return NULL;
-
- header = (http_header_entry_t *)list_find_first(
- headers, _http_header_find_key, (void *)name);
-
- if (header)
- return header->value;
- else
- return NULL;
-}
-
extern http_context_t *setup_http_context(conmgr_fd_t *con,
on_http_request_t on_http_request)
{
- http_context_t *context = _http_context_new();
+ http_context_t *context = xmalloc(sizeof(*context));
- xassert(context->magic == MAGIC);
- xassert(!context->con);
- xassert(!context->request);
+ context->magic = MAGIC;
context->con = con;
context->ref = conmgr_fd_new_ref(con);
context->on_http_request = on_http_request;
- /* Must use type since context->request is void ptr */
- context->request = xmalloc(sizeof(request_t));
_request_init(context);
return context;
@@ -815,7 +780,6 @@
extern void on_http_connection_finish(conmgr_fd_t *con, void *ctxt)
{
http_context_t *context = (http_context_t *) ctxt;
- request_t *request = NULL;
if (!context)
return;
@@ -824,19 +788,51 @@
http_parser_g_free_parse_request(&context->parser);
/* release request */
- request = context->request;
- xassert(request->magic == MAGIC_REQUEST_T);
_request_free_members(context);
- request->magic = ~MAGIC_REQUEST_T;
- xfree(context->request);
/* auth should have been released long before now */
xassert(!context->auth);
FREE_NULL_REST_AUTH(context->auth);
+ xassert(conmgr_fd_get_ref(context->ref) == context->con);
conmgr_fd_free_ref(&context->ref);
context->con = NULL;
context->magic = ~MAGIC;
xfree(context);
}
+
+extern void *http_context_get_auth(http_context_t *context)
+{
+ if (!context)
+ return NULL;
+
+ xassert(context->magic == MAGIC);
+
+ return context->auth;
+}
+
+extern void *http_context_set_auth(http_context_t *context, void *auth)
+{
+ void *old = NULL;
+
+ if (!context)
+ return auth;
+
+ xassert(context->magic == MAGIC);
+
+ old = context->auth;
+ context->auth = auth;
+
+ return old;
+}
+
+extern void http_context_free_null_auth(http_context_t *context)
+{
+ if (!context)
+ return;
+
+ xassert(context->magic == MAGIC);
+
+ FREE_NULL_REST_AUTH(context->auth);
+}
diff --git a/src/slurmrestd/http.h b/src/slurmrestd/http.h
index c219807..ec2aee7 100644
--- a/src/slurmrestd/http.h
+++ b/src/slurmrestd/http.h
@@ -43,7 +43,6 @@
#include "src/common/list.h"
#include "src/conmgr/conmgr.h"
-#include "src/interfaces/http_parser.h"
struct on_http_request_args_s;
typedef struct on_http_request_args_s on_http_request_args_t;
@@ -58,28 +57,17 @@
*/
typedef int (*on_http_request_t)(on_http_request_args_t *args);
-typedef struct {
- int magic;
- /* reference to assigned connection */
- conmgr_fd_ref_t *ref;
- /* assigned connection */
- conmgr_fd_t *con;
- /* Authentication context (auth_context_type_t) */
- void *auth;
- /* callback to call on each HTTP request */
- on_http_request_t on_http_request;
- /* http parser plugin state */
- http_parser_state_t *parser;
- /* http request_t */
- void *request;
-} http_context_t;
+/* Opaque connection context */
+typedef struct http_context_s http_context_t;
typedef struct on_http_request_args_s {
const http_request_method_t method; /* HTTP request method */
- list_t *headers; /* list of http_header_entry_t from client */
+ list_t *headers; /* list_t of http_header_t* from client */
const char *path; /* requested URL path (may be NULL) */
const char *query; /* requested URL query (may be NULL) */
http_context_t *context; /* calling context (do not xfree) */
+ conmgr_fd_ref_t *con; /* reference to connection */
+ const char *name; /* connection name */
uint16_t http_major; /* HTTP major version */
uint16_t http_minor; /* HTTP minor version */
const char *content_type; /* header content-type */
@@ -89,19 +77,6 @@
const char *body_encoding; /* body encoding type or NULL */
} on_http_request_args_t;
-typedef struct {
- char *name;
- char *value;
-} http_header_entry_t;
-extern void free_http_header(http_header_entry_t *);
-
-/* find http header from header list
- * IN headers List of http_header_entry_t
- * IN name name of header to find
- * RET ptr to header value or NULL if not found
- */
-extern const char *find_http_header(list_t *headers, const char *name);
-
/*
* Call back for new connection to setup HTTP
*
@@ -124,21 +99,14 @@
uint16_t http_major; /* HTTP major version */
uint16_t http_minor; /* HTTP minor version */
http_status_code_t status_code; /* HTTP status code to send */
- list_t *headers; /* list of http_header_entry_t to send (can be empty) */
+ /* list of http_header_entry_t to send (can be empty) */
+ list_t *headers; /* list_t of http_header_t* from client */
const char *body; /* body to send or NULL */
size_t body_length; /* bytes in body to send or 0 */
const char *body_encoding; /* body encoding type or NULL */
} send_http_response_args_t;
/*
- * Send HTTP close notification.
- * Warns the client that we are about to close the connection.
- * IN args arguments of response
- * RET SLURM_SUCCESS or error
- */
-extern int send_http_connection_close(http_context_t *ctxt);
-
-/*
* Send HTTP response
* IN args arguments of response
* RET SLURM_SUCCESS or error
@@ -161,4 +129,25 @@
*/
extern void on_http_connection_finish(conmgr_fd_t *con, void *ctxt);
+/*
+ * Get (arbitrary) auth pointer from context
+ * IN context - connection context
+ * RET auth pointer or NULL
+ */
+extern void *http_context_get_auth(http_context_t *context);
+
+/*
+ * Set and Get (arbitrary) auth pointer from context
+ * IN context - connection context
+ * IN auth - (arbitrary) auth pointer to set into context
+ * RET Prior auth pointer or auth arg if context==NULL
+ */
+extern void *http_context_set_auth(http_context_t *context, void *auth);
+
+/*
+ * Release and NULL auth pointer from context
+ * IN context - connection context
+ */
+extern void http_context_free_null_auth(http_context_t *context);
+
#endif /* SLURMRESTD_HTTP_H */
diff --git a/src/slurmrestd/operations.c b/src/slurmrestd/operations.c
index 4dfb9d5..b030a2a 100644
--- a/src/slurmrestd/operations.c
+++ b/src/slurmrestd/operations.c
@@ -46,6 +46,7 @@
#include "src/common/xstring.h"
#include "src/interfaces/serializer.h"
+#include "src/slurmrestd/http.h"
#include "src/slurmrestd/operations.h"
#include "src/slurmrestd/rest_auth.h"
@@ -76,11 +77,6 @@
float q; /* quality factor (priority) */
} http_header_accept_t;
-static const char *_name(const on_http_request_args_t *args)
-{
- return conmgr_fd_get_name(args->context->con);
-}
-
static void _check_path_magic(const path_t *path)
{
xassert(path->magic == PATH_MAGIC);
@@ -225,13 +221,12 @@
return rc;
}
-static int _operations_router_reject(const on_http_request_args_t *args,
+static int _operations_router_reject(on_http_request_args_t *args,
const char *err,
http_status_code_t err_code,
const char *body_encoding)
{
send_http_response_args_t send_args = {
- .con = args->context->con,
.headers = list_create(NULL),
.http_major = args->http_major,
.http_minor = args->http_minor,
@@ -240,18 +235,21 @@
.body_encoding = (body_encoding ? body_encoding : "text/plain"),
.body_length = (err ? strlen(err) : 0),
};
- http_header_entry_t close = {
+ http_header_t close = {
+ .magic = HTTP_HEADER_MAGIC,
.name = "Connection",
.value = "Close",
};
+ send_args.con = conmgr_fd_get_ref(args->con);
+
/* Always warn that connection will be closed after the body is sent */
list_append(send_args.headers, &close);
(void) send_http_response(&send_args);
/* close connection on error */
- conmgr_queue_close_fd(args->context->con);
+ conmgr_queue_close_fd(send_args.con);
FREE_NULL_LIST(send_args.headers);
@@ -408,7 +406,7 @@
*read_mime = MIME_TYPE_URL_ENCODED;
debug4("%s: [%s] did not provide a known content type header. Assuming URL encoded.",
- __func__, _name(args));
+ __func__, args->name);
}
if (args->accept) {
@@ -419,17 +417,17 @@
xassert(ptr->magic == MAGIC_HEADER_ACCEPT);
debug4("%s: [%s] accepts %s with q=%f",
- __func__, _name(args), ptr->type, ptr->q);
+ __func__, args->name, ptr->type, ptr->q);
if ((*write_mime = resolve_mime_type(ptr->type,
plugin_ptr))) {
debug4("%s: [%s] found accepts %s=%s with q=%f",
- __func__, _name(args), ptr->type,
+ __func__, args->name, ptr->type,
*write_mime, ptr->q);
break;
} else {
debug4("%s: [%s] rejecting accepts %s with q=%f",
- __func__, _name(args), ptr->type,
+ __func__, args->name, ptr->type,
ptr->q);
}
}
@@ -437,7 +435,7 @@
FREE_NULL_LIST(accept);
} else {
debug3("%s: [%s] Accept header not specified. Defaulting to JSON.",
- __func__, _name(args));
+ __func__, args->name);
*write_mime = MIME_TYPE_JSON;
}
@@ -478,14 +476,14 @@
* requests.
*/
debug("%s: [%s] Overriding content type from %s to %s for %s",
- __func__, _name(args), *read_mime, MIME_TYPE_URL_ENCODED,
+ __func__, args->name, *read_mime, MIME_TYPE_URL_ENCODED,
get_http_method_string(args->method));
*read_mime = MIME_TYPE_URL_ENCODED;
}
debug3("%s: [%s] mime read: %s write: %s",
- __func__, _name(args), *read_mime, *write_mime);
+ __func__, args->name, *read_mime, *write_mime);
return SLURM_SUCCESS;
}
@@ -500,22 +498,24 @@
data_t *resp = data_new();
char *body = NULL;
http_status_code_t e;
+ void *auth = NULL;
xassert(op_path);
debug3("%s: [%s] BEGIN: calling ctxt handler: 0x%"PRIXPTR"[%d] for path: %s",
- __func__, _name(args), (uintptr_t) op_path->callback,
+ __func__, args->name, (uintptr_t) op_path->callback,
callback_tag, args->path);
- rc = wrap_openapi_ctxt_callback(_name(args), args->method, params,
- query, callback_tag, resp,
- args->context->auth, parser, op_path,
- meta);
+ auth = http_context_set_auth(args->context, NULL);
+
+ rc = wrap_openapi_ctxt_callback(args->name, args->method, params, query,
+ callback_tag, resp, auth, parser,
+ op_path, meta);
/*
* Clear auth context after callback is complete. Client has to provide
* full auth for every request already.
*/
- FREE_NULL_REST_AUTH(args->context->auth);
+ FREE_NULL_REST_AUTH(auth);
if (data_get_type(resp) != DATA_TYPE_NULL) {
int rc2;
@@ -539,11 +539,11 @@
*
*/
send_http_response_args_t send_args = {
- .con = args->context->con,
.http_major = args->http_major,
.http_minor = args->http_minor,
.status_code = HTTP_STATUS_CODE_REDIRECT_NOT_MODIFIED,
};
+ send_args.con = conmgr_fd_get_ref(args->con);
e = send_args.status_code;
rc = send_http_response(&send_args);
} else if (rc && (rc != ESLURM_REST_EMPTY_RESULT)) {
@@ -580,7 +580,6 @@
rc = _operations_router_reject(args, body, e, write_mime);
} else {
send_http_response_args_t send_args = {
- .con = args->context->con,
.http_major = args->http_major,
.http_minor = args->http_minor,
.status_code = HTTP_STATUS_CODE_SUCCESS_OK,
@@ -588,6 +587,8 @@
.body_length = 0,
};
+ send_args.con = conmgr_fd_get_ref(args->con);
+
if (body) {
send_args.body = body;
send_args.body_length = strlen(body);
@@ -599,7 +600,7 @@
}
debug3("%s: [%s] END: calling handler: (0x%"PRIXPTR") callback_tag %d for path: %s rc[%d]=%s status[%d]=%s",
- __func__, _name(args), (uintptr_t) op_path->callback,
+ __func__, args->name, (uintptr_t) op_path->callback,
callback_tag, args->path, rc, slurm_strerror(rc), e,
get_http_status_code_string(e));
@@ -621,12 +622,12 @@
data_parser_t *parser = NULL;
info("%s: [%s] %s %s",
- __func__, _name(args), get_http_method_string(args->method),
+ __func__, args->name, get_http_method_string(args->method),
args->path);
if ((rc = rest_authenticate_http_request(args))) {
error("%s: [%s] authentication failed: %s",
- __func__, _name(args), slurm_strerror(rc));
+ __func__, args->name, slurm_strerror(rc));
_operations_router_reject(args, "Authentication failure",
HTTP_STATUS_CODE_ERROR_UNAUTHORIZED,
NULL);
@@ -653,7 +654,7 @@
slurm_rwlock_unlock(&paths_lock);
debug5("%s: [%s] found callback handler: (0x%"PRIXPTR") callback_tag=%d path=%s parser=%s",
- __func__, _name(args), (uintptr_t) path->op_path->callback,
+ __func__, args->name, (uintptr_t) path->op_path->callback,
callback_tag, args->path,
(parser ? data_parser_get_plugin(parser) : ""));
@@ -671,7 +672,7 @@
FREE_NULL_DATA(params);
/* always clear the auth context */
- FREE_NULL_REST_AUTH(args->context->auth);
+ http_context_free_null_auth(args->context);
return rc;
}
diff --git a/src/slurmrestd/plugins/auth/jwt/jwt.c b/src/slurmrestd/plugins/auth/jwt/jwt.c
index 7811b2e..2990a57 100644
--- a/src/slurmrestd/plugins/auth/jwt/jwt.c
+++ b/src/slurmrestd/plugins/auth/jwt/jwt.c
@@ -91,12 +91,12 @@
rest_auth_context_t *ctxt)
{
plugin_data_t *data;
- const char *key, *user_name, *bearer, *name;
+ const char *key, *user_name, *bearer;
+ const char *name = args->name;
key = find_http_header(args->headers, HTTP_HEADER_USER_TOKEN);
bearer = find_http_header(args->headers, HTTP_HEADER_AUTH);
user_name = find_http_header(args->headers, HTTP_HEADER_USER_NAME);
- name = conmgr_fd_get_name(args->context->con);
if (!key && !user_name && !bearer) {
debug3("%s: [%s] skipping token authentication",
diff --git a/src/slurmrestd/plugins/auth/local/local.c b/src/slurmrestd/plugins/auth/local/local.c
index f24f413..73084f6 100644
--- a/src/slurmrestd/plugins/auth/local/local.c
+++ b/src/slurmrestd/plugins/auth/local/local.c
@@ -134,15 +134,16 @@
const char *header_user_name)
{
int rc;
- const char *name = conmgr_fd_get_name(args->context->con);
+ const char *name = args->name;
+ conmgr_fd_t *con = conmgr_fd_get_ref(args->con);
uid_t cred_uid;
gid_t cred_gid;
pid_t cred_pid;
xassert(!ctxt->user_name);
- if ((rc = conmgr_get_fd_auth_creds(args->context->con, &cred_uid,
- &cred_gid, &cred_pid))) {
+ if ((rc = conmgr_get_fd_auth_creds(con, &cred_uid, &cred_gid,
+ &cred_pid))) {
/* socket may be remote, local auth doesn't apply */
debug("%s: [%s] unable to get socket ownership: %s",
__func__, name, slurm_strerror(rc));
@@ -245,11 +246,11 @@
struct stat status = { 0 };
const char *header_user_name = find_http_header(args->headers,
HTTP_HEADER_USER_NAME);
- const conmgr_fd_status_t cstatus =
- conmgr_fd_get_status(args->context->con);
- const int input_fd = conmgr_fd_get_input_fd(args->context->con);
- const int output_fd = conmgr_fd_get_output_fd(args->context->con);
- const char *name = conmgr_fd_get_name(args->context->con);
+ conmgr_fd_t *con = conmgr_fd_get_ref(args->con);
+ const conmgr_fd_status_t cstatus = conmgr_fd_get_status(con);
+ const int input_fd = conmgr_fd_get_input_fd(con);
+ const int output_fd = conmgr_fd_get_output_fd(con);
+ const char *name = args->name;
xassert(!ctxt->user_name);
diff --git a/src/slurmrestd/rest_auth.c b/src/slurmrestd/rest_auth.c
index 3148edf..3b1c379 100644
--- a/src/slurmrestd/rest_auth.c
+++ b/src/slurmrestd/rest_auth.c
@@ -164,18 +164,13 @@
extern int rest_authenticate_http_request(on_http_request_args_t *args)
{
int rc = ESLURM_AUTH_CRED_INVALID;
- rest_auth_context_t *context =
- (rest_auth_context_t *) args->context->auth;
-
- if (context) {
- fatal("%s: authentication context already set for connection: %s",
- __func__, conmgr_fd_get_name(args->context->con));
- }
-
- args->context->auth = context = rest_auth_g_new();
+ rest_auth_context_t *context = rest_auth_g_new();
_check_magic(context);
+ if (http_context_set_auth(args->context, context))
+ fatal_abort("authentication context already set for connection");
+
/* continue if already authenticated via plugin */
if (context->plugin_id)
return rest_auth_g_apply(context);
@@ -194,7 +189,10 @@
break;
}
- FREE_NULL_REST_AUTH(args->context->auth);
+ if (http_context_set_auth(args->context, NULL) != context)
+ fatal_abort("authentication context unexpectedly changed");
+
+ FREE_NULL_REST_AUTH(context);
return rc;
}