2
0
Эх сурвалжийг харах

add ability to serve files from pipe

Christian Grothoff 5 жил өмнө
parent
commit
1c4f23db74

+ 4 - 0
ChangeLog

@@ -1,3 +1,7 @@
+Sun 26 Jul 2020 01:56:54 PM CEST
+    Add MHD_create_response_from_pipe() to allow creating a response based
+    on data read from a pipe. -CG
+
 Fri Jul 10 15:04:51 CEST 2020
     Fixed Postprocessor URL-encoded parsing if '%' fell on boundary. -CG/MD
 

+ 15 - 0
doc/libmicrohttpd.texi

@@ -2018,6 +2018,21 @@ Return @code{NULL} on error (i.e. invalid arguments, out of memory).
 @end deftypefun
 
 
+@deftypefun {struct MHD_Response *} MHD_create_response_from_pipe (uint64_t size, int fd)
+Create a response object.  The response object can be extended with
+header information and then it can be used ONLY ONCE.
+
+@table @var
+@item fd
+file descriptor of the read-end of the pipe; will be
+closed when response is destroyed.
+The descriptor should be in blocking-IO mode.
+@end table
+
+Return @code{NULL} on error (i.e. out of memory).
+@end deftypefun
+
+
 @deftypefun {struct MHD_Response *} MHD_create_response_from_fd_at_offset (size_t size, int fd, off_t offset)
 Create a response object.  The response object can be extended with
 header information and then it can be used any number of times.

+ 17 - 3
src/include/microhttpd.h

@@ -180,7 +180,7 @@ enum MHD_Result
 #define _MHD_EXTERN extern
 #elif defined (_WIN32) && defined(MHD_W32DLL)
 /* Define MHD_W32DLL when using MHD as W32 .DLL to speed up linker a little */
-#define _MHD_EXTERN __declspec (dllimport)
+#define _MHD_EXTERN __declspec(dllimport)
 #else
 #define _MHD_EXTERN extern
 #endif
@@ -262,10 +262,10 @@ typedef SOCKET MHD_socket;
 #ifndef _MHD_DEPR_FUNC
 #if defined(_MSC_FULL_VER) && _MSC_VER + 0 >= 1400
 /* VS 2005 or later */
-#define _MHD_DEPR_FUNC(msg) __declspec (deprecated (msg))
+#define _MHD_DEPR_FUNC(msg) __declspec(deprecated (msg))
 #elif defined(_MSC_FULL_VER) && _MSC_VER + 0 >= 1310
 /* VS .NET 2003 deprecation do not support custom messages */
-#define _MHD_DEPR_FUNC(msg) __declspec (deprecated)
+#define _MHD_DEPR_FUNC(msg) __declspec(deprecated)
 #elif (__GNUC__ + 0 >= 5) || (defined (__clang__) && \
   (__clang_major__ + 0 > 2 || (__clang_major__ + 0 == 2 && __clang_minor__ >= \
                                9)))                                             /* FIXME: earlier versions not tested */
@@ -3125,6 +3125,20 @@ MHD_create_response_from_fd (size_t size,
                              int fd);
 
 
+/**
+ * Create a response object.  The response object can be extended with
+ * header information and then be used ONLY ONCE.
+ *
+ * @param fd file descriptor referring to a read-end of a pipe with the
+ *        data; will be closed when response is destroyed;
+ *        fd should be in 'blocking' mode
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ * @ingroup response
+ */
+_MHD_EXTERN struct MHD_Response *
+MHD_create_response_from_pipe (int fd);
+
+
 /**
  * Create a response object.  The response object can be extended with
  * header information and then be used any number of times.

+ 3 - 0
src/microhttpd/connection.c

@@ -3957,11 +3957,14 @@ MHD_queue_response (struct MHD_Connection *connection,
   connection->responseCode = status_code;
 #if defined(_MHD_HAVE_SENDFILE)
   if ( (response->fd == -1) ||
+       (response->is_pipe) ||
        (0 != (connection->daemon->options & MHD_USE_TLS)) )
     connection->resp_sender = MHD_resp_sender_std;
   else
     connection->resp_sender = MHD_resp_sender_sendfile;
 #endif /* _MHD_HAVE_SENDFILE */
+  /* FIXME: if 'is_pipe' is set, TLS is off, and we have *splice*, we could use splice()
+     to avoid two user-space copies... */
 
   if ( ( (NULL != connection->method) &&
          (MHD_str_equal_caseless_ (connection->method,

+ 5 - 0
src/microhttpd/internal.h

@@ -400,6 +400,11 @@ struct MHD_Response
    */
   enum MHD_ResponseFlags flags;
 
+  /**
+   * If the @e fd is a pipe (no sendfile()).
+   */
+  bool is_pipe;
+
 };
 
 

+ 61 - 0
src/microhttpd/response.c

@@ -526,6 +526,37 @@ file_reader (void *cls,
 }
 
 
+/**
+ * Given a pipe descriptor, read data from the pipe
+ * to generate the response.
+ *
+ * @param cls pointer to the response
+ * @param pos offset in the pipe to access (ignored)
+ * @param buf where to write the data
+ * @param max number of bytes to write at most
+ * @return number of bytes written
+ */
+static ssize_t
+pipe_reader (void *cls,
+             uint64_t pos,
+             char *buf,
+             size_t max)
+{
+  struct MHD_Response *response = cls;
+  ssize_t n;
+
+  (void) pos;
+  n = read (response->fd,
+            buf,
+            max);
+  if (0 == n)
+    return MHD_CONTENT_READER_END_OF_STREAM;
+  if (n < 0)
+    return MHD_CONTENT_READER_END_WITH_ERROR;
+  return n;
+}
+
+
 /**
  * Destroy file reader context.  Closes the file
  * descriptor.
@@ -614,12 +645,42 @@ MHD_create_response_from_fd_at_offset64 (uint64_t size,
   if (NULL == response)
     return NULL;
   response->fd = fd;
+  response->is_pipe = false;
   response->fd_off = offset;
   response->crc_cls = response;
   return response;
 }
 
 
+/**
+ * Create a response object.  The response object can be extended with
+ * header information and then be used ONLY ONCE.
+ *
+ * @param fd file descriptor referring to a read-end of a pipe with the
+ *        data; will be closed when response is destroyed;
+ *        fd should be in 'blocking' mode
+ * @return NULL on error (i.e. invalid arguments, out of memory)
+ * @ingroup response
+ */
+_MHD_EXTERN struct MHD_Response *
+MHD_create_response_from_pipe (int fd)
+{
+  struct MHD_Response *response;
+
+  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
+                                                MHD_FILE_READ_BLOCK_SIZE,
+                                                &pipe_reader,
+                                                NULL,
+                                                &free_callback);
+  if (NULL == response)
+    return NULL;
+  response->fd = fd;
+  response->is_pipe = true;
+  response->crc_cls = response;
+  return response;
+}
+
+
 /**
  * Create a response object.  The response object can be extended with
  * header information and then be used any number of times.