GNU libmicrohttpd  0.9.72
response_from_fd.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2007-2019 Daniel Pittman, Christian Grothoff and
4  Karlson2k (Evgeny Grin)
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 
28 #include "internal.h"
29 
30 
35 #ifndef MHD_FILE_READ_BLOCK_SIZE
36 #ifdef _WIN32
37 #define MHD_FILE_READ_BLOCK_SIZE 16384 /* 16k */
38 #else /* _WIN32 */
39 #define MHD_FILE_READ_BLOCK_SIZE 4096 /* 4k */
40 #endif /* _WIN32 */
41 #endif /* !MHD_FD_BLOCK_SIZE */
42 
53 static ssize_t
54 file_reader (void *cls,
55  uint64_t pos,
56  char *buf,
57  size_t max)
58 {
59  struct MHD_Response *response = cls;
60 #if ! defined(_WIN32) || defined(__CYGWIN__)
61  ssize_t n;
62 #else /* _WIN32 && !__CYGWIN__ */
63  const HANDLE fh = (HANDLE) _get_osfhandle (response->fd);
64 #endif /* _WIN32 && !__CYGWIN__ */
65  const int64_t offset64 = (int64_t) (pos + response->fd_off);
66 
67  if (offset64 < 0)
68  return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
69 
70 #if ! defined(_WIN32) || defined(__CYGWIN__)
71  if (max > SSIZE_MAX)
72  max = SSIZE_MAX; /* Clamp to maximum return value. */
73 
74 #if defined(HAVE_PREAD64)
75  n = pread64 (response->fd,
76  buf,
77  max,
78  offset64);
79 #elif defined(HAVE_PREAD)
80  if ( (sizeof(off_t) < sizeof (uint64_t)) &&
81  (offset64 > (uint64_t) INT32_MAX) )
82  return MHD_CONTENT_READER_END_WITH_ERROR; /* Read at required position is not possible. */
83 
84  n = pread (response->fd,
85  buf,
86  max,
87  (off_t) offset64);
88 #else /* ! HAVE_PREAD */
89 #if defined(HAVE_LSEEK64)
90  if (lseek64 (response->fd,
91  offset64,
92  SEEK_SET) != offset64)
93  return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
94 #else /* ! HAVE_LSEEK64 */
95  if ( (sizeof(off_t) < sizeof (uint64_t)) &&
96  (offset64 > (uint64_t) INT32_MAX) )
97  return MHD_CONTENT_READER_END_WITH_ERROR; /* seek to required position is not possible */
98 
99  if (lseek (response->fd,
100  (off_t) offset64,
101  SEEK_SET) != (off_t) offset64)
102  return MHD_CONTENT_READER_END_WITH_ERROR; /* can't seek to required position */
103 #endif /* ! HAVE_LSEEK64 */
104  n = read (response->fd,
105  buf,
106  max);
107 
108 #endif /* ! HAVE_PREAD */
109  if (0 == n)
111  if (n < 0)
113  return n;
114 #else /* _WIN32 && !__CYGWIN__ */
115  if (INVALID_HANDLE_VALUE == fh)
116  return MHD_CONTENT_READER_END_WITH_ERROR; /* Value of 'response->fd' is not valid. */
117  else
118  {
119  OVERLAPPED f_ol = {0, 0, {{0, 0}}, 0}; /* Initialize to zero. */
120  ULARGE_INTEGER pos_uli;
121  DWORD toRead = (max > INT32_MAX) ? INT32_MAX : (DWORD) max;
122  DWORD resRead;
123 
124  pos_uli.QuadPart = (uint64_t) offset64; /* Simple transformation 64bit -> 2x32bit. */
125  f_ol.Offset = pos_uli.LowPart;
126  f_ol.OffsetHigh = pos_uli.HighPart;
127  if (! ReadFile (fh,
128  (void*) buf,
129  toRead,
130  &resRead,
131  &f_ol))
132  return MHD_CONTENT_READER_END_WITH_ERROR; /* Read error. */
133  if (0 == resRead)
135  return (ssize_t) resRead;
136  }
137 #endif /* _WIN32 && !__CYGWIN__ */
138 }
139 
140 
147 static void
148 free_callback (void *cls)
149 {
150  struct MHD_Response *response = cls;
151 
152  (void) close (response->fd);
153  response->fd = -1;
154 }
155 
156 
175 struct MHD_Response *
176 MHD_response_from_fd (enum MHD_HTTP_StatusCode sc,
177  int fd,
178  uint64_t offset,
179  uint64_t size)
180 {
181  struct MHD_Response *response;
182 
183  mhd_assert (-1 != fd);
184 #if ! defined(HAVE___LSEEKI64) && ! defined(HAVE_LSEEK64)
185  if ( (sizeof (uint64_t) > sizeof (off_t)) &&
186  ( (size > (uint64_t) INT32_MAX) ||
187  (offset > (uint64_t) INT32_MAX) ||
188  ((size + offset) >= (uint64_t) INT32_MAX) ) )
189  return NULL;
190 #endif
191  if ( ((int64_t) size < 0) ||
192  ((int64_t) offset < 0) ||
193  ((int64_t) (size + offset) < 0) )
194  return NULL;
195 
196  response = MHD_response_from_callback (sc,
197  size,
199  &file_reader,
200  NULL,
201  &free_callback);
202  if (NULL == response)
203  return NULL;
204  response->fd = fd;
205  response->fd_off = offset;
206  response->crc_cls = response;
207  return response;
208 }
209 
210 
211 /* end of response_from_fd.c */
struct MHD_Response * MHD_response_from_fd(enum MHD_HTTP_StatusCode sc, int fd, uint64_t offset, uint64_t size)
struct MHD_Response * MHD_response_from_callback(enum MHD_HTTP_StatusCode sc, uint64_t size, size_t block_size, MHD_ContentReaderCallback crc, void *crc_cls, MHD_ContentReaderFreeCallback crfc)
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
#define INT32_MAX
Definition: mhd_limits.h:65
#define NULL
Definition: reason_phrase.c:30
internal shared structures
#define SSIZE_MAX
Definition: mhd_limits.h:111
int off_t offset
Definition: microhttpd.h:3196
#define MHD_CONTENT_READER_END_OF_STREAM
Definition: microhttpd.h:175
int fd
Definition: microhttpd.h:3195
#define MHD_CONTENT_READER_END_WITH_ERROR
Definition: microhttpd.h:176
static void free_callback(void *cls)
#define MHD_FILE_READ_BLOCK_SIZE
static ssize_t file_reader(void *cls, uint64_t pos, char *buf, size_t max)
void * crc_cls
Definition: internal.h:1594
uint64_t fd_off
Definition: internal.h:1653