+ return add_raw_socket(s, fd);
+}
+
+/**********************************************************************
+ **********************************************************************
+ **********************************************************************/
+
+static RemoteSource *request_meta(void **connection_cls) {
+ RemoteSource *source;
+
+ assert(connection_cls);
+ if (*connection_cls)
+ return *connection_cls;
+
+ source = new0(RemoteSource, 1);
+ if (!source)
+ return NULL;
+ source->fd = -1;
+
+ log_debug("Added RemoteSource as connection metadata %p", source);
+
+ *connection_cls = source;
+ return source;
+}
+
+static void request_meta_free(void *cls,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ enum MHD_RequestTerminationCode toe) {
+ RemoteSource *s;
+
+ assert(connection_cls);
+ s = *connection_cls;
+
+ log_debug("Cleaning up connection metadata %p", s);
+ source_free(s);
+ *connection_cls = NULL;
+}
+
+static int process_http_upload(
+ struct MHD_Connection *connection,
+ const char *upload_data,
+ size_t *upload_data_size,
+ RemoteSource *source) {
+
+ bool finished = false;
+ int r;
+
+ assert(source);
+
+ log_debug("request_handler_upload: connection %p, %zu bytes",
+ connection, *upload_data_size);
+
+ if (*upload_data_size) {
+ log_info("Received %zu bytes", *upload_data_size);
+
+ r = push_data(source, upload_data, *upload_data_size);
+ if (r < 0) {
+ log_error("Failed to store received data of size %zu: %s",
+ *upload_data_size, strerror(-r));
+ return mhd_respond_oom(connection);
+ }
+ *upload_data_size = 0;
+ } else
+ finished = true;
+
+ while (true) {
+ r = process_source(source, &server->writer, arg_compress, arg_seal);
+ if (r == -E2BIG)
+ log_warning("Entry too big, skipped");
+ else if (r == -EAGAIN || r == -EWOULDBLOCK)
+ break;
+ else if (r < 0) {
+ log_warning("Failed to process data for connection %p", connection);
+ return mhd_respondf(connection, MHD_HTTP_UNPROCESSABLE_ENTITY,
+ "Processing failed: %s", strerror(-r));
+ }
+ }
+
+ if (!finished)
+ return MHD_YES;
+
+ /* The upload is finished */
+
+ if (source_non_empty(source)) {
+ log_warning("EOF reached with incomplete data");
+ return mhd_respond(connection, MHD_HTTP_EXPECTATION_FAILED,
+ "Trailing data not processed.");
+ }
+
+ return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
+};
+
+static int request_handler(
+ void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data,
+ size_t *upload_data_size,
+ void **connection_cls) {
+
+ const char *header;
+ int r ,code;
+
+ assert(connection);
+ assert(connection_cls);
+ assert(url);
+ assert(method);
+
+ log_debug("Handling a connection %s %s %s", method, url, version);
+
+ if (*connection_cls)
+ return process_http_upload(connection,
+ upload_data, upload_data_size,
+ *connection_cls);
+
+ if (!streq(method, "POST"))
+ return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
+ "Unsupported method.\n");
+
+ if (!streq(url, "/upload"))
+ return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
+ "Not found.\n");
+
+ header = MHD_lookup_connection_value(connection,
+ MHD_HEADER_KIND, "Content-Type");
+ if (!header || !streq(header, "application/vnd.fdo.journal"))
+ return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
+ "Content-Type: application/vnd.fdo.journal"
+ " is required.\n");
+
+ if (trust_pem) {
+ r = check_permissions(connection, &code);
+ if (r < 0)
+ return code;
+ }
+
+ if (!request_meta(connection_cls))
+ return respond_oom(connection);
+ return MHD_YES;
+}
+
+static int setup_microhttpd_server(RemoteServer *s, int fd, bool https) {
+ struct MHD_OptionItem opts[] = {
+ { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
+ { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
+ { MHD_OPTION_LISTEN_SOCKET, fd},
+ { MHD_OPTION_END},
+ { MHD_OPTION_END},
+ { MHD_OPTION_END},
+ { MHD_OPTION_END}};
+ int opts_pos = 3;
+ int flags =
+ MHD_USE_DEBUG |
+ MHD_USE_PEDANTIC_CHECKS |
+ MHD_USE_EPOLL_LINUX_ONLY |
+ MHD_USE_DUAL_STACK;
+
+ const union MHD_DaemonInfo *info;
+ int r, epoll_fd;
+ MHDDaemonWrapper *d;
+
+ assert(fd >= 0);
+
+ r = fd_nonblock(fd, true);