aboutsummaryrefslogtreecommitdiff
path: root/src/lib/response_from_fd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/response_from_fd.c')
-rw-r--r--src/lib/response_from_fd.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/src/lib/response_from_fd.c b/src/lib/response_from_fd.c
new file mode 100644
index 00000000..ea486600
--- /dev/null
+++ b/src/lib/response_from_fd.c
@@ -0,0 +1,198 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file lib/response_from_fd.c
22 * @brief implementation of MHD_response_from_fd()
23 * @author Daniel Pittman
24 * @author Christian Grothoff
25 * @author Karlson2k (Evgeny Grin)
26 */
27#include "internal.h"
28
29
30/**
31 * Given a file descriptor, read data from the file
32 * to generate the response.
33 *
34 * @param cls pointer to the response
35 * @param pos offset in the file to access
36 * @param buf where to write the data
37 * @param max number of bytes to write at most
38 * @return number of bytes written
39 */
40static ssize_t
41file_reader (void *cls,
42 uint64_t pos,
43 char *buf,
44 size_t max)
45{
46 struct MHD_Response *response = cls;
47#if !defined(_WIN32) || defined(__CYGWIN__)
48 ssize_t n;
49#else /* _WIN32 && !__CYGWIN__ */
50 const HANDLE fh = (HANDLE) _get_osfhandle (response->fd);
51#endif /* _WIN32 && !__CYGWIN__ */
52 const int64_t offset64 = (int64_t)(pos + response->fd_off);
53
54 if (offset64 < 0)
55 return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
56
57#if !defined(_WIN32) || defined(__CYGWIN__)
58 if (max > SSIZE_MAX)
59 max = SSIZE_MAX; /* Clamp to maximum return value. */
60
61#if defined(HAVE_PREAD64)
62 n = pread64 (response->fd,
63 buf,
64 max,
65 offset64);
66#elif defined(HAVE_PREAD)
67 if ( (sizeof(off_t) < sizeof (uint64_t)) &&
68 (offset64 > (uint64_t)INT32_MAX) )
69 return MHD_CONTENT_READER_END_WITH_ERROR; /* Read at required position is not possible. */
70
71 n = pread (response->fd,
72 buf,
73 max,
74 (off_t) offset64);
75#else /* ! HAVE_PREAD */
76#if defined(HAVE_LSEEK64)
77 if (lseek64 (response->fd,
78 offset64,
79 SEEK_SET) != offset64)
80 return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
81#else /* ! HAVE_LSEEK64 */
82 if ( (sizeof(off_t) < sizeof (uint64_t)) &&
83 (offset64 > (uint64_t)INT32_MAX) )
84 return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
85
86 if (lseek (response->fd,
87 (off_t) offset64,
88 SEEK_SET) != (off_t) offset64)
89 return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
90#endif /* ! HAVE_LSEEK64 */
91 n = read (response->fd,
92 buf,
93 max);
94
95#endif /* ! HAVE_PREAD */
96 if (0 == n)
97 return MHD_CONTENT_READER_END_OF_STREAM;
98 if (n < 0)
99 return MHD_CONTENT_READER_END_WITH_ERROR;
100 return n;
101#else /* _WIN32 && !__CYGWIN__ */
102 if (INVALID_HANDLE_VALUE == fh)
103 return MHD_CONTENT_READER_END_WITH_ERROR; /* Value of 'response->fd' is not valid. */
104 else
105 {
106 OVERLAPPED f_ol = {0, 0, {{0, 0}}, 0}; /* Initialize to zero. */
107 ULARGE_INTEGER pos_uli;
108 DWORD toRead = (max > INT32_MAX) ? INT32_MAX : (DWORD) max;
109 DWORD resRead;
110
111 pos_uli.QuadPart = (uint64_t) offset64; /* Simple transformation 64bit -> 2x32bit. */
112 f_ol.Offset = pos_uli.LowPart;
113 f_ol.OffsetHigh = pos_uli.HighPart;
114 if (! ReadFile (fh,
115 (void*)buf,
116 toRead,
117 &resRead,
118 &f_ol))
119 return MHD_CONTENT_READER_END_WITH_ERROR; /* Read error. */
120 if (0 == resRead)
121 return MHD_CONTENT_READER_END_OF_STREAM;
122 return (ssize_t) resRead;
123 }
124#endif /* _WIN32 && !__CYGWIN__ */
125}
126
127
128/**
129 * Destroy file reader context. Closes the file
130 * descriptor.
131 *
132 * @param cls pointer to file descriptor
133 */
134static void
135free_callback (void *cls)
136{
137 struct MHD_Response *response = cls;
138
139 (void) close (response->fd);
140 response->fd = -1;
141}
142
143
144/**
145 * Create a response object based on an @a fd from which
146 * data is read. The response object can be extended with
147 * header information and then be used any number of times.
148 *
149 * @param sc status code to return
150 * @param fd file descriptor referring to a file on disk with the
151 * data; will be closed when response is destroyed;
152 * fd should be in 'blocking' mode
153 * @param offset offset to start reading from in the file;
154 * reading file beyond 2 GiB may be not supported by OS or
155 * MHD build; see ::MHD_FEATURE_LARGE_FILE
156 * @param size size of the data portion of the response;
157 * sizes larger than 2 GiB may be not supported by OS or
158 * MHD build; see ::MHD_FEATURE_LARGE_FILE
159 * @return NULL on error (i.e. invalid arguments, out of memory)
160 * @ingroup response
161 */
162struct MHD_Response *
163MHD_response_from_fd (enum MHD_HTTP_StatusCode sc,
164 int fd,
165 uint64_t offset,
166 uint64_t size)
167{
168 struct MHD_Response *response;
169
170 mhd_assert (-1 != fd);
171#if !defined(HAVE___LSEEKI64) && !defined(HAVE_LSEEK64)
172 if ( (sizeof (uint64_t) > sizeof (off_t)) &&
173 ( (size > (uint64_t)INT32_MAX) ||
174 (offset > (uint64_t)INT32_MAX) ||
175 ((size + offset) >= (uint64_t)INT32_MAX) ) )
176 return NULL;
177#endif
178 if ( ((int64_t) size < 0) ||
179 ((int64_t) offset < 0) ||
180 ((int64_t) (size + offset) < 0) )
181 return NULL;
182
183 response = MHD_response_from_callback (size,
184 4 * 1024,
185 &file_reader,
186 NULL,
187 &free_callback);
188 if (NULL == response)
189 return NULL;
190 response->fd = fd;
191 response->status_code = sc;
192 response->fd_off = offset;
193 response->crc_cls = response;
194 return response;
195}
196
197/* end of response_from_fd.c */
198