1 /* $NetBSD: file_http.cpp,v 1.3 2001/03/22 18:19:36 uch Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <file.h> 40 #include <file_http.h> 41 #include <console.h> 42 43 #if _WIN32_WCE < 210 44 #define tolower(c) ((c) - 'A' + 'a') 45 #define wcsicmp _wcsicmp 46 #endif 47 48 static int __stricmp(const char *, const char *); 49 50 HttpFile::HttpFile(Console *&cons) 51 : File(cons), 52 _req_get("GET "), 53 _req_head("HEAD "), 54 _req_host(" HTTP/1.0\r\nHOST: "), 55 _req_ua("\r\nUser-Agent: HPCBOOT/ZERO(1st impact; Windows CE; " 56 #if defined MIPS 57 "MIPS" 58 #elif defined ARM 59 "ARM" 60 #elif defined SH3 61 "SH3" 62 #elif defined SH4 63 "SH4" 64 #else 65 "Unknown" 66 #endif 67 ")\r\n\r\n") 68 { 69 _server_name[0] = '\0'; 70 _debug = TRUE; 71 _memory_cache = TRUE; 72 // _memory_cache = FALSE; // not recomended. 73 _buffer = 0; 74 _reset_state(); 75 DPRINTF((TEXT("File: HTTP\n"))); 76 } 77 78 HttpFile::~HttpFile(void) 79 { 80 if (_buffer) 81 free(_buffer); 82 WSACleanup(); 83 } 84 85 void 86 HttpFile::_reset_state(void) 87 { 88 _ascii_filename[0] = '\0'; 89 _cached = FALSE; 90 if (_buffer) 91 free(_buffer); 92 _buffer = 0; 93 _header_size = 0; 94 _cur_pos = 0; 95 } 96 97 BOOL 98 HttpFile::setRoot(TCHAR *server) 99 { 100 SOCKET h; 101 int ret, port; 102 103 // parse server name and its port # 104 TCHAR sep[] = TEXT(":/"); 105 TCHAR *token = wcstok(server, sep); 106 for (int i = 0; i < 3 && token; i++, token = wcstok(0, sep)) { 107 switch(i) { 108 case 0: 109 if (wcsicmp(token, TEXT("http"))) { 110 return FALSE; 111 } 112 break; 113 case 1: 114 if (!_to_ascii(_server_name, token, MAX_PATH)) 115 return FALSE; 116 port = 80; 117 break; 118 case 2: 119 port = _wtoi(token); 120 break; 121 } 122 } 123 124 ret = WSAStartup(MAKEWORD(1, 1), &_winsock); 125 if (ret != 0) { 126 DPRINTF((TEXT("WinSock initialize failed.\n"))); 127 return FALSE; 128 } 129 if (LOBYTE(_winsock.wVersion) != 1 || 130 HIBYTE(_winsock.wVersion) != 1) { 131 DPRINTF((TEXT("can't use WinSock DLL.\n"))); 132 return FALSE; 133 } 134 135 h = socket(AF_INET, SOCK_STREAM, 0); 136 if (h == INVALID_SOCKET) { 137 DPRINTF((TEXT("can't open socket. cause=%d\n"), 138 WSAGetLastError())); 139 return FALSE; 140 } 141 142 struct hostent *entry = gethostbyname(_server_name); 143 if (entry == 0) { 144 DPRINTF((TEXT("can't get host by name.\n"))); 145 return FALSE; 146 } 147 148 memset(&_sockaddr, 0, sizeof(sockaddr_in)); 149 _sockaddr.sin_family = AF_INET; 150 _sockaddr.sin_port = htons(port); 151 for (u_int8_t **addr_list =(u_int8_t **)entry->h_addr_list; 152 *addr_list; addr_list++) { 153 u_int8_t *b = &_sockaddr.sin_addr.S_un.S_un_b.s_b1; 154 for (int i = 0; i < 4; i++) 155 b[i] = addr_list[0][i]; 156 157 DPRINTF((TEXT("%d.%d.%d.%d "), b[0], b[1], b[2], b[3])); 158 if (connect(h,(const struct sockaddr *)&_sockaddr, 159 sizeof(struct sockaddr_in)) == 0) 160 goto connected; 161 } 162 DPRINTF((TEXT("can't connect server.\n"))); 163 return FALSE; 164 165 connected: 166 DPRINTF((TEXT(" \"%S\"\n"), _server_name)); 167 closesocket(h); 168 169 return TRUE; 170 } 171 172 BOOL 173 HttpFile::open(const TCHAR *name, u_int32_t flag) 174 { 175 _reset_state(); 176 return _to_ascii(_ascii_filename, name, MAX_PATH); 177 } 178 179 size_t 180 HttpFile::_read_from_cache(void *buf, size_t bytes, off_t ofs) 181 { 182 size_t transfer; 183 184 if (ofs >= _buffer_size) 185 return 0; 186 187 transfer = ofs + bytes > _buffer_size ? _buffer_size - ofs : bytes; 188 189 memcpy(buf, &_buffer[ofs], transfer); 190 191 return transfer; 192 } 193 194 BOOL 195 HttpFile::seek(off_t offset) 196 { 197 _cur_pos = offset; 198 199 return TRUE; 200 } 201 202 size_t 203 HttpFile::read(void *buf, size_t bytes, off_t offset) 204 { 205 char *b; 206 off_t ofs; 207 208 if (offset != -1) { 209 ofs = offset; 210 } else { 211 ofs = _cur_pos; 212 _cur_pos += bytes; 213 } 214 215 if (_memory_cache && _cached) 216 return _read_from_cache(buf, bytes, ofs); 217 218 // HEAD request(get header size). 219 if (_header_size == 0) 220 _buffer_size = _parse_header(_header_size); 221 222 // reconnect 223 Socket sock(_sockaddr); 224 SOCKET h; 225 if ((h = sock) == INVALID_SOCKET) 226 return 0; 227 228 // GET request 229 strcpy(_request, _req_get); 230 _set_request(); 231 send(h, _request, strlen(_request), 0); 232 233 // skip header. 234 b = static_cast <char *>(malloc(_header_size)); 235 _recv_buffer(h, b, _header_size); 236 free(b); 237 238 // read contents. 239 size_t readed; 240 if (_memory_cache) { 241 _buffer = static_cast <char *>(malloc(_buffer_size)); 242 _recv_buffer(h, _buffer, _buffer_size); 243 _cached = TRUE; 244 return _read_from_cache(buf, bytes, ofs); 245 } else { 246 int i, n = ofs / bytes; 247 b = static_cast <char *>(buf); 248 249 for (readed = 0, i = 0; i < n; i++) 250 readed += _recv_buffer(h, b, bytes); 251 if ((n =(ofs % bytes))) 252 readed += _recv_buffer(h, b, n); 253 DPRINTF((TEXT("skip contents %d byte.\n"), readed)); 254 255 readed = _recv_buffer(h, b, bytes); 256 } 257 return readed; 258 } 259 260 size_t 261 HttpFile::_parse_header(size_t &header_size) 262 { 263 size_t sz = 0; 264 // reconnect. 265 Socket sock(_sockaddr); 266 SOCKET h; 267 if ((h = sock) == INVALID_SOCKET) 268 return 0; 269 270 // HEAD request 271 strcpy(_request, _req_head); 272 _set_request(); 273 send(h, _request, strlen(_request), 0); 274 275 // receive. 276 char __buf[TMP_BUFFER_SIZE]; 277 int cnt, ret; 278 279 for (cnt = 0; 280 ret = _recv_buffer(h, __buf, TMP_BUFFER_SIZE); cnt += ret) { 281 char sep[] = " :\r\n"; 282 char *token = strtok(__buf, sep); 283 while (token) { 284 if (__stricmp(token, "content-length") == 0) { 285 token = strtok(0, sep); 286 sz = atoi(token); 287 DPRINTF((TEXT("content-length=%d\n"), sz)); 288 } else 289 token = strtok(0, sep); 290 } 291 } 292 header_size = cnt; 293 DPRINTF((TEXT("header %d byte contents %d byte\n"), header_size, sz)); 294 295 return sz; 296 } 297 298 size_t 299 HttpFile::_recv_buffer(SOCKET h, char *buf, size_t size) 300 { 301 size_t cnt, total = 0; 302 303 do { 304 cnt = recv(h, buf + total, size - total, 0); 305 total += cnt; 306 DPRINTFN(2,(TEXT("size %d readed %d byte(+%d)\n"), 307 size, total, cnt)); 308 } while (total < size && cnt > 0); 309 310 311 DPRINTFN(1,(TEXT("total read %d byte\n"), total)); 312 return total; 313 } 314 315 void 316 HttpFile::_set_request(void) 317 { 318 strcat(_request, _ascii_filename); 319 strcat(_request, _req_host); 320 strcat(_request, _server_name); 321 strcat(_request, _req_ua); 322 } 323 324 static int 325 __stricmp(const char *s1, const char *s2) 326 { 327 const unsigned char *us1 = 328 reinterpret_cast <const unsigned char *>(s1); 329 const unsigned char *us2 = 330 reinterpret_cast <const unsigned char *>(s2); 331 332 while (tolower(*us1) == tolower(*us2++)) 333 if (*us1++ == '\0') 334 return 0; 335 return tolower(*us1) - tolower(*--us2); 336 } 337 338 Socket::Socket(struct sockaddr_in &sock) 339 : _sockaddr(sock) 340 { 341 _socket = socket(AF_INET, SOCK_STREAM, 0); 342 if (_socket != INVALID_SOCKET) 343 connect(_socket, 344 reinterpret_cast <const struct sockaddr *>(&_sockaddr), 345 sizeof(struct sockaddr_in)); 346 } 347 348 Socket::~Socket(void) 349 { 350 if (_socket != INVALID_SOCKET) 351 closesocket(_socket); 352 } 353