URLStorage.C 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $XConsortium: URLStorage.C /main/1 1996/07/29 17:07:01 cde-hp $ */
  24. // Copyright (c) 1995 James Clark
  25. // See the file COPYING for copying permission.
  26. #ifdef __GNUG__
  27. #pragma implementation
  28. #endif
  29. // FIXME This implementation won't work on an EBCDIC machine.
  30. #include "splib.h"
  31. #ifdef WINSOCK
  32. #include <winsock.h>
  33. #define readsocket(s, p, n) ::recv(s, p, n, 0)
  34. #define writesocket(s, p, n) ::send(s, p, n, 0)
  35. #define errnosocket (WSAGetLastError())
  36. #define SocketMessageArg(n) WinsockMessageArg(n)
  37. #define SOCKET_EINTR (WSAEINTR)
  38. #define SP_HAVE_SOCKET
  39. #else
  40. #ifdef SP_HAVE_SOCKET
  41. #include <sys/types.h>
  42. #include <sys/socket.h>
  43. #include <netdb.h>
  44. #include <netinet/in.h>
  45. #include <arpa/inet.h>
  46. #ifdef SP_INCLUDE_UNISTD_H
  47. #include <unistd.h>
  48. #endif
  49. #ifdef SP_INCLUDE_OSFCN_H
  50. #include <osfcn.h>
  51. #endif
  52. typedef int SOCKET;
  53. #define SOCKET_ERROR (-1)
  54. #define INVALID_SOCKET (-1)
  55. #define SOCKET_EINTR (EINTR)
  56. #define closesocket(s) close(s)
  57. #define writesocket(fd, p, n) ::write(fd, p, n)
  58. #define readsocket(s, p, n) ::read(s, p, n)
  59. #define errnosocket (errno)
  60. #define SocketMessageArg(n) ErrnoMessageArg(n)
  61. #include "ErrnoMessageArg.h"
  62. #endif /* SP_HAVE_SOCKET */
  63. #endif /* not WINSOCK */
  64. #include "URLStorage.h"
  65. #include "URLStorageMessages.h"
  66. #include "RewindStorageObject.h"
  67. #include "UnivCharsetDesc.h"
  68. #include "MessageArg.h"
  69. #include "MessageBuilder.h"
  70. #include "macros.h"
  71. #include <stdlib.h>
  72. #include <string.h>
  73. #include <errno.h>
  74. #include <stddef.h>
  75. #include <ctype.h>
  76. #include <stdio.h>
  77. #ifdef SP_NAMESPACE
  78. namespace SP_NAMESPACE {
  79. #endif
  80. static UnivCharsetDesc::Range range = { 0, 128, 0 };
  81. static UnivCharsetDesc iso646Charset(&range, 1);
  82. #ifdef SP_HAVE_SOCKET
  83. class HttpSocketStorageObject : public RewindStorageObject {
  84. public:
  85. HttpSocketStorageObject(SOCKET fd, Boolean mayRewind, const StringC &hostStr);
  86. ~HttpSocketStorageObject();
  87. Boolean open(const String<char> &path, Messenger &);
  88. Boolean read(char *buf, size_t bufSize, Messenger &mgr, size_t &nread);
  89. Boolean seekToStart(Messenger &);
  90. static SOCKET openHttp(const String<char> &host,
  91. unsigned short port,
  92. const StringC &hostStr,
  93. Messenger &mgr);
  94. private:
  95. HttpSocketStorageObject(const HttpSocketStorageObject &); // undefined
  96. void operator=(const HttpSocketStorageObject &); // undefined
  97. Boolean readHeader(Messenger &);
  98. Boolean readLine(Messenger &mgr, String<char> &line, String<char> &leftOver);
  99. StringC hostStr_;
  100. String<char> path_;
  101. Boolean eof_;
  102. SOCKET fd_;
  103. };
  104. #ifdef WINSOCK
  105. class WinsockMessageArg : public MessageArg {
  106. public:
  107. WinsockMessageArg(int n) : n_(n) { }
  108. MessageArg *copy() const { return new WinsockMessageArg(*this); }
  109. void append(MessageBuilder &) const;
  110. private:
  111. int n_;
  112. };
  113. void WinsockMessageArg::append(MessageBuilder &builder) const
  114. {
  115. // I can't figure out how to get a string associated
  116. // with this error number. FormatMessage() doesn't seem
  117. // to work.
  118. builder.appendFragment(URLStorageMessages::winsockErrorNumber);
  119. builder.appendNumber(n_);
  120. }
  121. class WinsockIniter {
  122. public:
  123. WinsockIniter();
  124. ~WinsockIniter();
  125. Boolean init(Messenger &mgr);
  126. private:
  127. Boolean inited_;
  128. Boolean initSuccess_;
  129. };
  130. static WinsockIniter winsockIniter;
  131. WinsockIniter::WinsockIniter()
  132. : inited_(0)
  133. {
  134. }
  135. WinsockIniter::~WinsockIniter()
  136. {
  137. if (inited_ && initSuccess_)
  138. (void)WSACleanup();
  139. }
  140. Boolean WinsockIniter::init(Messenger &mgr)
  141. {
  142. if (!inited_) {
  143. inited_ = 1;
  144. initSuccess_ = 0;
  145. WORD version = MAKEWORD(1, 1);
  146. WSADATA wsaData;
  147. int err = WSAStartup(version, &wsaData);
  148. if (err)
  149. mgr.message(URLStorageMessages::winsockInitialize,
  150. WinsockMessageArg(err));
  151. else if (LOBYTE(wsaData.wVersion) != 1
  152. || HIBYTE(wsaData.wVersion) != 1) {
  153. mgr.message(URLStorageMessages::winsockVersion);
  154. WSACleanup();
  155. }
  156. else
  157. initSuccess_ = 1;
  158. }
  159. return initSuccess_;
  160. }
  161. #endif /* WINSOCK */
  162. #endif /* SP_HAVE_SOCKET */
  163. URLStorageManager::URLStorageManager(const char *type)
  164. : type_(type), IdStorageManager(iso646Charset)
  165. {
  166. }
  167. const char *URLStorageManager::type() const
  168. {
  169. return type_;
  170. }
  171. Boolean URLStorageManager::guessIsId(const StringC &id,
  172. const CharsetInfo &charset) const
  173. {
  174. if (id.size() < 8)
  175. return 0;
  176. size_t i = 0;
  177. for (const char *s = "http://"; *s; s++, i++)
  178. if (id[i] != charset.execToDesc(*s)
  179. && (!islower(*s) || id[i] != charset.execToDesc(toupper(*s))))
  180. return 0;
  181. return 1;
  182. }
  183. StorageObject *URLStorageManager::makeStorageObject(const StringC &specId,
  184. const StringC &baseId,
  185. Boolean,
  186. Boolean mayRewind,
  187. Messenger &mgr,
  188. StringC &id)
  189. {
  190. #ifdef SP_HAVE_SOCKET
  191. id = specId;
  192. resolveRelative(baseId, id, 0);
  193. if (id.size() < 5
  194. || (id[0] != 'h' && id[0] != 'H')
  195. || (id[1] != 't' && id[1] != 'T')
  196. || (id[2] != 't' && id[2] != 'T')
  197. || (id[3] != 'p' && id[3] != 'P')
  198. || id[4] != ':') {
  199. mgr.message(URLStorageMessages::onlyHTTP);
  200. return 0;
  201. }
  202. if (id.size() < 7 || id[5] != '/' || id[6] != '/') {
  203. mgr.message(URLStorageMessages::badRelative,
  204. StringMessageArg(id));
  205. return 0;
  206. }
  207. size_t i = 7;
  208. String<char> host;
  209. while (i < id.size()) {
  210. if (id[i] == '/')
  211. break;
  212. if (id[i] == ':')
  213. break;
  214. host += char(id[i]);
  215. i++;
  216. }
  217. if (host.size() == 0) {
  218. mgr.message(URLStorageMessages::emptyHost,
  219. StringMessageArg(id));
  220. return 0;
  221. }
  222. unsigned short port;
  223. if (i < id.size() && id[i] == ':') {
  224. i++;
  225. String<char> digits;
  226. while (i < id.size() && id[i] != '/') {
  227. digits += char(id[i]);
  228. i++;
  229. }
  230. if (digits.size() == 0) {
  231. mgr.message(URLStorageMessages::emptyPort,
  232. StringMessageArg(id));
  233. return 0;
  234. }
  235. digits += '\0';
  236. char *endptr;
  237. long n = strtol(digits.data(), &endptr, 10);
  238. if (endptr != digits.data() + digits.size() - 1
  239. || n < 0
  240. || n > 65535L) {
  241. mgr.message(URLStorageMessages::invalidPort,
  242. StringMessageArg(id));
  243. return 0;
  244. }
  245. port = (unsigned short)n;
  246. }
  247. else
  248. port = 80;
  249. String<char> path;
  250. if (i < id.size()) {
  251. while (i < id.size() && id[i] != '#') {
  252. path += char(id[i]);
  253. i++;
  254. }
  255. }
  256. if (path.size() == 0)
  257. path += '/';
  258. StringC hostStr;
  259. for (i = 0; i < host.size(); i++)
  260. hostStr += host[i];
  261. host += '\0';
  262. SOCKET fd = HttpSocketStorageObject::openHttp(host, port, hostStr, mgr);
  263. if (fd == INVALID_SOCKET)
  264. return 0;
  265. HttpSocketStorageObject *p
  266. = new HttpSocketStorageObject(fd, mayRewind, hostStr);
  267. if (!p->open(path, mgr)) {
  268. delete p;
  269. return 0;
  270. }
  271. return p;
  272. #else /* not SP_HAVE_SOCKET */
  273. ParentLocationMessenger(mgr).message(URLStorageMessages::notSupported);
  274. return 0;
  275. #endif /* not SP_HAVE_SOCKET */
  276. }
  277. Boolean URLStorageManager::resolveRelative(const StringC &baseId,
  278. StringC &id,
  279. Boolean) const
  280. {
  281. static const char schemeChars[] =
  282. "abcdefghijklmnopqrstuvwxyz"
  283. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  284. "01234567879"
  285. "+-.";
  286. size_t i;
  287. // If it has a scheme, it is absolute.
  288. for (i = 0; i < id.size(); i++) {
  289. if (id[i] == ':') {
  290. if (i == 0)
  291. break;
  292. else
  293. return 1;
  294. }
  295. else if (!strchr(schemeChars, id[i]))
  296. break;
  297. }
  298. for (i = 0; i < id.size(); i++) {
  299. if (id[i] != '/')
  300. break;
  301. }
  302. size_t slashCount = i;
  303. if (slashCount > 0) {
  304. Boolean foundSameSlash = 0;
  305. size_t sameSlashPos;
  306. for (size_t j = 0; j < baseId.size(); j++) {
  307. size_t thisSlashCount = 0;
  308. for (size_t k = j; k < baseId.size() && baseId[k] == '/'; k++)
  309. thisSlashCount++;
  310. if (thisSlashCount == slashCount && !foundSameSlash) {
  311. foundSameSlash = 1;
  312. sameSlashPos = j;
  313. }
  314. else if (thisSlashCount > slashCount)
  315. foundSameSlash = 0;
  316. }
  317. if (foundSameSlash) {
  318. StringC tem(baseId.data(), sameSlashPos);
  319. tem += id;
  320. tem.swap(id);
  321. }
  322. }
  323. else {
  324. size_t j;
  325. for (j = baseId.size(); j > 0; j--)
  326. if (baseId[j - 1] == '/')
  327. break;
  328. if (j > 0) {
  329. StringC tem(baseId.data(), j);
  330. tem += id;
  331. tem.swap(id);
  332. }
  333. }
  334. // FIXME remove xxx/../, and /.
  335. return 1;
  336. }
  337. Boolean URLStorageManager::transformNeutral(StringC &str, Boolean fold,
  338. Messenger &) const
  339. {
  340. if (fold)
  341. for (size_t i = 0; i < str.size(); i++) {
  342. Char c = str[i];
  343. if (c <= (unsigned char)-1)
  344. str[i] = tolower(str[i]);
  345. }
  346. return 1;
  347. }
  348. #ifdef SP_HAVE_SOCKET
  349. SOCKET HttpSocketStorageObject::openHttp(const String<char> &host,
  350. unsigned short port,
  351. const StringC &hostStr,
  352. Messenger &mgr)
  353. {
  354. #ifdef WINSOCK
  355. if (!winsockIniter.init(mgr))
  356. return INVALID_SOCKET;
  357. #endif
  358. struct sockaddr_in sock;
  359. sock.sin_family = AF_INET;
  360. sock.sin_port = htons(port);
  361. if (isdigit((unsigned char)host[0])) {
  362. unsigned long n = inet_addr(host.data());
  363. if (n == (unsigned long)-1) {
  364. ParentLocationMessenger(mgr).message(URLStorageMessages::invalidHostNumber,
  365. StringMessageArg(hostStr));
  366. return INVALID_SOCKET;
  367. }
  368. sock.sin_addr.s_addr = n;
  369. }
  370. else {
  371. struct hostent *hp = gethostbyname(host.data());
  372. if (!hp) {
  373. const MessageType1 *message;
  374. switch (h_errno) {
  375. case HOST_NOT_FOUND:
  376. message = &URLStorageMessages::hostNotFound;
  377. break;
  378. case TRY_AGAIN:
  379. message = &URLStorageMessages::hostTryAgain;
  380. break;
  381. case NO_RECOVERY:
  382. message = &URLStorageMessages::hostNoRecovery;
  383. break;
  384. case NO_DATA:
  385. #ifdef NO_ADDRESS
  386. #if NO_ADDRESS != NO_DATA
  387. case NO_ADDRESS:
  388. #endif
  389. #endif
  390. message = &URLStorageMessages::hostNoData;
  391. break;
  392. default:
  393. #ifdef WINSOCK
  394. ParentLocationMessenger(mgr).message(URLStorageMessages::hostOtherError,
  395. StringMessageArg(hostStr),
  396. WinsockMessageArg(h_errno));
  397. return INVALID_SOCKET;
  398. #else
  399. message = &URLStorageMessages::hostUnknownError;
  400. break;
  401. #endif
  402. }
  403. ParentLocationMessenger(mgr).message(*message,
  404. StringMessageArg(hostStr));
  405. return INVALID_SOCKET;
  406. }
  407. memcpy(&sock.sin_addr, hp->h_addr, hp->h_length);
  408. }
  409. SOCKET fd = socket(PF_INET, SOCK_STREAM, 0);
  410. if (fd == INVALID_SOCKET) {
  411. ParentLocationMessenger(mgr).message(URLStorageMessages::cannotCreateSocket,
  412. SocketMessageArg(errnosocket));
  413. return INVALID_SOCKET;
  414. }
  415. if (connect(fd, (struct sockaddr *)&sock, sizeof(sock)) == SOCKET_ERROR) {
  416. ParentLocationMessenger(mgr).message(URLStorageMessages::cannotConnect,
  417. StringMessageArg(hostStr),
  418. SocketMessageArg(errnosocket));
  419. (void)closesocket(fd);
  420. return INVALID_SOCKET;
  421. }
  422. return fd;
  423. }
  424. HttpSocketStorageObject::HttpSocketStorageObject(SOCKET fd,
  425. Boolean mayRewind,
  426. const StringC &hostStr)
  427. : RewindStorageObject(mayRewind, 0), hostStr_(hostStr), fd_(fd), eof_(0)
  428. {
  429. }
  430. HttpSocketStorageObject::~HttpSocketStorageObject()
  431. {
  432. if (fd_ != INVALID_SOCKET)
  433. (void)closesocket(fd_);
  434. }
  435. Boolean HttpSocketStorageObject::open(const String<char> &path, Messenger &mgr)
  436. {
  437. path_ = path;
  438. String<char> request;
  439. request.append("GET ", 4);
  440. request += path_;
  441. request += ' ';
  442. request.append("HTTP/1.0\r\n\r\n", 12);
  443. // FIXME check length of write
  444. if (writesocket(fd_, request.data(), request.size()) == SOCKET_ERROR) {
  445. ParentLocationMessenger(mgr).message(URLStorageMessages::writeError,
  446. StringMessageArg(hostStr_),
  447. SocketMessageArg(errnosocket));
  448. (void)closesocket(fd_);
  449. fd_ = INVALID_SOCKET;
  450. return 0;
  451. }
  452. if (!readHeader(mgr)) {
  453. (void)closesocket(fd_);
  454. fd_ = INVALID_SOCKET;
  455. return 0;
  456. }
  457. return 1;
  458. }
  459. Boolean HttpSocketStorageObject::readHeader(Messenger &mgr)
  460. {
  461. String<char> buf;
  462. String<char> leftOver;
  463. if (!readLine(mgr, buf, leftOver))
  464. return 0;
  465. buf += '\0';
  466. static const char ver[] = "HTTP/1.0";
  467. int i;
  468. for (i = 0; ver[i]; i++)
  469. if (ver[i] != buf[i])
  470. break;
  471. if (ver[i]) {
  472. if (buf.size() > 0)
  473. unread(buf.data(), buf.size() - 1);
  474. return 1;
  475. }
  476. const char *ptr = &buf[i];
  477. while (isspace((unsigned char)*ptr))
  478. ptr++;
  479. int val = 0;
  480. while (isdigit((unsigned char)*ptr)) {
  481. val = val*10 + *ptr - '0';
  482. ptr++;
  483. }
  484. while (isspace((unsigned char)*ptr))
  485. ptr++;
  486. if (val < 200 || val >= 300) {
  487. StringC reason;
  488. while (*ptr && *ptr != '\n' && *ptr != '\r') {
  489. reason += Char(*ptr);
  490. ptr++;
  491. }
  492. StringC pathStr;
  493. for (size_t i = 0; i < path_.size(); i++)
  494. pathStr += path_[i];
  495. ParentLocationMessenger(mgr).message(URLStorageMessages::getFailed,
  496. StringMessageArg(hostStr_),
  497. StringMessageArg(pathStr),
  498. StringMessageArg(reason));
  499. return 0;
  500. }
  501. for (;;) {
  502. if (!readLine(mgr, buf, leftOver))
  503. return 0;
  504. if (buf.size() == 0 || buf[0] == '\r' || buf[0] == '\n')
  505. break;
  506. }
  507. if (leftOver.size())
  508. unread(leftOver.data(), leftOver.size());
  509. return 1;
  510. }
  511. // True will be returned for an empty line.
  512. Boolean HttpSocketStorageObject::readLine(Messenger &mgr,
  513. String<char> &line,
  514. String<char> &leftOver)
  515. {
  516. line.resize(0);
  517. Boolean hadCr = 0;
  518. Boolean gotLine = 0;
  519. size_t li;
  520. for (li = 0; li < leftOver.size(); li++) {
  521. if (leftOver[li] == '\r') {
  522. if (hadCr) {
  523. gotLine = 1;
  524. break;
  525. }
  526. line += '\r';
  527. hadCr = 1;
  528. }
  529. else if (leftOver[li] == '\n') {
  530. line += '\n';
  531. li++;
  532. gotLine = 1;
  533. break;
  534. }
  535. else if (hadCr) {
  536. gotLine = 1;
  537. break;
  538. }
  539. else
  540. line += leftOver[li];
  541. }
  542. if (gotLine) {
  543. for (size_t i = li; i < leftOver.size(); i++)
  544. leftOver[i - li] = leftOver[i];
  545. leftOver.resize(leftOver.size() - li);
  546. return 1;
  547. }
  548. leftOver.resize(0);
  549. if (eof_)
  550. return 1;
  551. for (;;) {
  552. char c;
  553. long n;
  554. do {
  555. n = readsocket(fd_, &c, 1);
  556. } while (n < 0 && errnosocket == SOCKET_EINTR);
  557. if (n == 0) {
  558. (void)closesocket(fd_);
  559. eof_ = 1;
  560. return 1;
  561. }
  562. if (n < 0) {
  563. ParentLocationMessenger(mgr).message(URLStorageMessages::readError,
  564. StringMessageArg(hostStr_),
  565. SocketMessageArg(errnosocket));
  566. (void)closesocket(fd_);
  567. fd_ = INVALID_SOCKET;
  568. return 0;
  569. }
  570. switch (c) {
  571. case '\r':
  572. if (hadCr) {
  573. leftOver += c;
  574. return 1;
  575. }
  576. hadCr = 1;
  577. line += c;
  578. break;
  579. case '\n':
  580. line += c;
  581. return 1;
  582. default:
  583. if (hadCr) {
  584. leftOver += c;
  585. return 1;
  586. }
  587. line += c;
  588. break;
  589. }
  590. }
  591. return 0; // not reached
  592. }
  593. Boolean HttpSocketStorageObject::read(char *buf, size_t bufSize, Messenger &mgr,
  594. size_t &nread)
  595. {
  596. if (readSaved(buf, bufSize, nread))
  597. return 1;
  598. if (fd_ == INVALID_SOCKET || eof_)
  599. return 0;
  600. long n;
  601. do {
  602. n = readsocket(fd_, buf, bufSize);
  603. } while (n < 0 && errnosocket == SOCKET_EINTR);
  604. if (n > 0) {
  605. nread = size_t(n);
  606. saveBytes(buf, nread);
  607. return 1;
  608. }
  609. if (n < 0) {
  610. ParentLocationMessenger(mgr).message(URLStorageMessages::readError,
  611. StringMessageArg(hostStr_),
  612. SocketMessageArg(errnosocket));
  613. fd_ = INVALID_SOCKET;
  614. }
  615. else {
  616. eof_ = 1;
  617. if (closesocket(fd_) == SOCKET_ERROR)
  618. ParentLocationMessenger(mgr).message(URLStorageMessages::closeError,
  619. StringMessageArg(hostStr_),
  620. SocketMessageArg(errnosocket));
  621. fd_ = INVALID_SOCKET;
  622. }
  623. return 0;
  624. }
  625. Boolean HttpSocketStorageObject::seekToStart(Messenger &)
  626. {
  627. CANNOT_HAPPEN();
  628. return 0;
  629. }
  630. #endif /* SP_HAVE_SOCKET */
  631. #ifdef SP_NAMESPACE
  632. }
  633. #endif