Revert "Use a variable on the stack to not have a temporary in the call"
[ACE_TAO.git] / ACE / apps / JAWS / clients / Blobby / Blob_Handler.cpp
blobbc2bfc507da346c68c8cab2980bb7c18303b1066
1 #include "Blob_Handler.h"
2 #include "ace/OS_NS_stdio.h"
3 #include "ace/OS_NS_string.h"
4 #include "ace/OS_NS_strings.h"
6 // Empty constructor for compliance with new Connector behavior.
7 ACE_Blob_Handler::ACE_Blob_Handler ()
11 // Always use this constructor
12 ACE_Blob_Handler::ACE_Blob_Handler (ACE_Message_Block * mb,
13 size_t length,
14 size_t offset,
15 ACE_TCHAR *filename) :
16 mb_ (mb),
17 length_ (length),
18 offset_ (offset),
19 filename_ (ACE_OS::strdup (filename)),
20 bytecount_ (0)
24 ACE_Blob_Handler::~ACE_Blob_Handler ()
26 if (filename_)
28 ACE_OS::free ((void *) filename_);
29 filename_ = 0;
33 // Called by Connector after connection is established
34 int
35 ACE_Blob_Handler::open (void *)
37 if (this->send_request () != 0)
38 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Blob_Handler::open():send_request failed"), -1);
40 if (this->receive_reply () != 0)
41 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Blob_Handler::open():receive_reply failed"), -1);
42 return 0;
45 // No-op
46 int
47 ACE_Blob_Handler::close (u_long flags)
49 ACE_UNUSED_ARG (flags);
50 return 0;
54 // Always overridden by the derived classes
55 int
56 ACE_Blob_Handler::send_request ()
58 return -1;
61 // Always overridden by the derived classes
62 int
63 ACE_Blob_Handler::receive_reply ()
65 return -1;
68 // used to retrieve the number of bytes read/written by the
69 // last operation on the Blob
70 int
71 ACE_Blob_Handler::byte_count ()
73 return bytecount_;
76 // Reader **************************************************
78 ACE_Blob_Reader::ACE_Blob_Reader (ACE_Message_Block * mb,
79 size_t length,
80 size_t offset,
81 ACE_TCHAR *filename,
82 const char *request_prefix,
83 const char *request_suffix) :
84 ACE_Blob_Handler (mb, length, offset, filename),
85 request_prefix_ (request_prefix),
86 request_suffix_ (request_suffix)
90 // Send the HTTP request
91 int
92 ACE_Blob_Reader::send_request ()
94 char mesg [MAX_HEADER_SIZE];
96 // Check to see if the request is too big
97 if (MAX_HEADER_SIZE < (ACE_OS::strlen (request_prefix_)
98 + ACE_OS::strlen (filename_)
99 + ACE_OS::strlen (request_suffix_) + 4))
100 ACE_ERROR_RETURN((LM_ERROR,"Request too large!"), -1);
102 // Create a message to send to the server requesting retrieval of the file
103 int len = ACE_OS::sprintf (mesg, "%s %s %s",
104 request_prefix_,
105 ACE_TEXT_ALWAYS_CHAR (filename_),
106 request_suffix_);
108 // Send the message to server
109 if (peer ().send_n (mesg, len) != len)
110 ACE_ERROR_RETURN((LM_ERROR,"Error sending request"), -1);
113 return 0;
116 // Recieve the HTTP Reply
118 ACE_Blob_Reader::receive_reply ()
120 ssize_t len;
121 char buf [MAX_HEADER_SIZE + 1];
122 char *buf_ptr;
123 size_t bytes_read = 0;
124 size_t bytes_left = this->length_;
125 size_t offset_left = this->offset_;
127 // Receive the first MAX_HEADER_SIZE bytes to be able to strip off the
128 // header. Note that we assume that the header will fit into the
129 // first MAX_HEADER_SIZE bytes of the transmitted data.
130 if ((len = peer ().recv_n (buf, MAX_HEADER_SIZE)) >= 0)
132 buf[len] = '\0';
134 // Search for the header termination string "\r\n\r\n", or "\n\n". If
135 // found, move past it to get to the data portion.
136 if ((buf_ptr = ACE_OS::strstr (buf,"\r\n\r\n")) != 0)
137 buf_ptr += 4;
138 else if ((buf_ptr = ACE_OS::strstr (buf, "\n\n")) != 0)
139 buf_ptr += 2;
140 else
141 buf_ptr = buf;
143 // Determine number of data bytes read. This is equal to the
144 // total bytes read minus number of header bytes.
145 bytes_read = (buf + len) - buf_ptr;
147 else
148 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_Blob_Reader::receiveReply():Error while reading header"), -1);
150 // ***************************************************************
151 // At this point, we have stripped off the header and are ready to
152 // process data. buf_ptr points to the data
154 // First adjust for offset. There are two cases:
155 // (1) The first block of data encountered the offset. In this case
156 // we simply increment the buf_ptr by offset.
157 // (2) The first block of data did not encounter the offset. That
158 // is, the offset needs to go past the number of data bytes already read.
159 if (bytes_read > offset_left)
161 // The first case is true -- that is offset is less than the
162 // data bytes we just read.
163 buf_ptr += offset_left;
165 // Determine how many data bytes are actually there. This is
166 // basically the total number of data bytes we read minus any
167 // offset we have.
168 size_t data_bytes = bytes_read - offset_left;
170 // Check for the case where the bytes read are enough to fulfill
171 // our request (for length bytes). If this is the case, then we
172 // don't need to do any extra recvs and can simply return with
173 // the data.
174 if (data_bytes >= bytes_left)
176 // The first block contains enough data to satisfy the
177 // length. So copy the data into the message buffer.
178 if (mb_->copy (buf_ptr, bytes_left) == -1)
179 ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
180 "ACE Blob_Reader::receiveReply():Error copying data into Message_Block"), -1);
181 bytecount_ = length_;
182 return 0;
185 // Copy over all the data bytes into our message buffer.
186 if (mb_->copy (buf_ptr, data_bytes) == -1)
187 ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
188 "ACE_Blob_Reader::receiveReply():Error copying data into Message_Block" ), -1);
190 // Adjust bytes left
191 bytes_left -= data_bytes;
193 // No more offset left. So set it to zero.
194 offset_left = 0;
196 else
198 // The second case is true -- that is offset is greater than
199 // the data bytes we just read.
200 offset_left -= bytes_read;
203 // If we ad any offset left, take care of that.
204 while (offset_left > 0)
206 // MAX_HEADER_SIZE in which case we should do a receive of
207 // offset bytes into a temporary buffer. Otherwise, we should
208 // receive MAX_HEADER_SIZE bytes into temporary buffer and
209 // decrement offset_left.
210 if (offset_left < (sizeof buf))
211 len = offset_left;
212 else
213 len = sizeof buf;
214 if (peer().recv_n (buf, len) != len)
215 ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
216 "ACE_Blob_Reader::receiveReply():Read error" ),
217 -1);
218 offset_left -= len;
221 // *****************************************************************
222 // At this point we are all set to receive the actual data which the
223 // user wants. We have made adjustments for offset and are ready to
224 // receive the actual data. Receive the data directly into the
225 // message buffer.
227 len = peer().recv_n (mb_->wr_ptr (), bytes_left);
229 if (len < 0 || static_cast<size_t> (len) != bytes_left)
230 ACE_ERROR_RETURN ((LM_ERROR, "%p\n",
231 "ACE_Blob_Reader::receiveReply():Read error" ),
232 -1);
234 // Adjust the message buffer write pointer by number of bytes we
235 // received.
236 mb_->wr_ptr (len);
238 // Set the byte count to number of bytes received
239 this->bytecount_ = length_;
241 return 0;
244 // Writer **************************************************
246 ACE_Blob_Writer::ACE_Blob_Writer (ACE_Message_Block * mb,
247 size_t length,
248 size_t offset,
249 ACE_TCHAR *filename,
250 const char *request_prefix,
251 const char *request_suffix) :
252 ACE_Blob_Handler (mb, length, offset, filename),
253 request_prefix_ (request_prefix),
254 request_suffix_ (request_suffix)
259 ACE_Blob_Writer::send_request ()
261 // Check for sanity -- check if we have any data to send.
262 if (offset_+ length_ > mb_->length ())
263 ACE_ERROR_RETURN((LM_ERROR, "%p\n",
264 "ACE_Blob_Writer::sendRequest():Invalid offset/length"), -1);
266 // Determine the length of the header message we will be sending to
267 // the server. Note that we add 32 for safety -- this corresponds to
268 // the number of bytes needed for the length field.
269 size_t mesglen =
270 ACE_OS::strlen (request_prefix_)
271 + ACE_OS::strlen (filename_)
272 + ACE_OS::strlen (request_suffix_)
273 + 32; // safety
275 // Allocate a buffer to hold the header
276 char *mesg = 0;
277 ACE_NEW_RETURN (mesg, char [mesglen], -1);
279 // Create the header, store the actual length in mesglen.
280 mesglen = ACE_OS::sprintf (mesg, "%s /%s %s " ACE_SIZE_T_FORMAT_SPECIFIER_ASCII "\n\n",
281 request_prefix_, ACE_TEXT_ALWAYS_CHAR (filename_),
282 request_suffix_, length_);
284 // Send the header followed by the data
286 // First send the header
287 if (peer ().send_n (mesg, mesglen) == -1)
288 ACE_ERROR_RETURN((LM_ERROR, "%p\n", "Error sending request"), -1);
290 // "Consume" the offset by moving the read pointer of the message
291 // buffer
292 mb_->rd_ptr (offset_);
294 // Now send the data
295 if (peer ().send_n (mb_->rd_ptr (), length_) != (int)length_)
296 ACE_ERROR_RETURN((LM_ERROR, "%p\n", "Error sending file"), -1);
298 // Adjust the read pointer of the mesage buffer
299 mb_->rd_ptr (length_);
301 return 0;
305 ACE_Blob_Writer::receive_reply ()
307 // Allocate a buffer big enough to hold the header
308 char buf[MAX_HEADER_SIZE];
310 // Receive the reply from the server
311 size_t num_recvd = 0;
312 ssize_t len = peer ().recv_n (buf, sizeof buf - 1, 0, &num_recvd); // reserve one byte to store the \0
313 if (len ==-1)
314 ACE_ERROR_RETURN((LM_ERROR, "%p\n", "Error reading header"), -1);
316 buf [num_recvd] = 0;
318 // Parse the header
319 char *lasts = 0;
321 // First check if this was a valid header -- HTTP/1.0
322 char *token = ACE_OS::strtok_r (buf, " \t", &lasts);
324 if ( (token == 0) || (ACE_OS::strcasecmp (token, "HTTP/1.0") != 0))
325 ACE_ERROR_RETURN((LM_ERROR, "%p\n", "Did not receive a HTTP/1.0 response"), -1);
327 // Get the return code.
328 int return_code = ACE_OS::atoi (ACE_OS::strtok_r (0, " \t", &lasts));
330 // Check if the transaction succeeded. The only success codes are in
331 // the range of 200-299 (HTTP specification).
332 if (return_code >= 200 && return_code < 300)
333 return 0;
334 else
336 // Something went wrong!
337 // Get the description from the header message of what went wrong.
338 char *description = ACE_OS::strtok_r (0, "\n\r", &lasts);
339 ACE_ERROR_RETURN((LM_ERROR, "%p\n", description), -1);
341 ACE_NOTREACHED(return 0);