📄 urlstorage.cxx
字号:
// Copyright (c) 1995 James Clark// See the file COPYING for copying permission.#ifdef __GNUG__#pragma implementation#endif// FIXME This implementation won't work on an EBCDIC machine.#include "splib.h"#ifdef WINSOCK#include <winsock.h>#define readsocket(s, p, n) ::recv(s, p, n, 0)#define writesocket(s, p, n) ::send(s, p, n, 0)#define errnosocket (WSAGetLastError())#define SocketMessageArg(n) WinsockMessageArg(n)#define SOCKET_EINTR (WSAEINTR)#define SP_HAVE_SOCKET#else#ifdef SP_HAVE_SOCKET#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include <netinet/in.h>#include <arpa/inet.h>#ifdef SP_INCLUDE_UNISTD_H#include <unistd.h>#endif#ifdef SP_INCLUDE_OSFCN_H#include <osfcn.h>#endif#ifdef SP_DECLARE_H_ERRNOextern int h_errno;#endiftypedef int SOCKET;#define SOCKET_ERROR (-1)#define INVALID_SOCKET (-1)#define SOCKET_EINTR (EINTR)#define closesocket(s) close(s)#define writesocket(fd, p, n) ::write(fd, p, n)#define readsocket(s, p, n) ::read(s, p, n)#define errnosocket (errno)#define SocketMessageArg(n) ErrnoMessageArg(n)#include "ErrnoMessageArg.h"#endif /* SP_HAVE_SOCKET */#endif /* not WINSOCK */#include "URLStorage.h"#include "URLStorageMessages.h"#include "RewindStorageObject.h"#include "UnivCharsetDesc.h"#include "MessageArg.h"#include "MessageBuilder.h"#include "macros.h"#include <stdlib.h>#include <string.h>#include <errno.h>#include <stddef.h>#include <ctype.h>#include <stdio.h>#ifdef SP_NAMESPACEnamespace SP_NAMESPACE {#endifstatic UnivCharsetDesc::Range range = { 0, 128, 0 };static CharsetInfo iso646Charset(UnivCharsetDesc(&range, 1));#ifdef SP_HAVE_SOCKETclass HttpSocketStorageObject : public RewindStorageObject {public: HttpSocketStorageObject(SOCKET fd, Boolean mayRewind, const StringC &hostStr); ~HttpSocketStorageObject(); Boolean open(const String<char> &path, Messenger &); Boolean read(char *buf, size_t bufSize, Messenger &mgr, size_t &nread); Boolean seekToStart(Messenger &); static SOCKET openHttp(const String<char> &host, unsigned short port, const StringC &hostStr, Messenger &mgr);private: HttpSocketStorageObject(const HttpSocketStorageObject &); // undefined void operator=(const HttpSocketStorageObject &); // undefined Boolean readHeader(Messenger &); Boolean readLine(Messenger &mgr, String<char> &line, String<char> &leftOver); static Boolean parseStatus(const char *&ptr, int &val); StringC hostStr_; String<char> path_; Boolean eof_; SOCKET fd_;};#ifdef WINSOCKclass WinsockMessageArg : public MessageArg {public: WinsockMessageArg(int n) : n_(n) { } MessageArg *copy() const { return new WinsockMessageArg(*this); } void append(MessageBuilder &) const;private: int n_;};void WinsockMessageArg::append(MessageBuilder &builder) const{ // I can't figure out how to get a string associated // with this error number. FormatMessage() doesn't seem // to work. builder.appendFragment(URLStorageMessages::winsockErrorNumber); builder.appendNumber(n_);}class WinsockIniter {public: WinsockIniter(); ~WinsockIniter(); Boolean init(Messenger &mgr);private: Boolean inited_; Boolean initSuccess_;};static WinsockIniter winsockIniter;WinsockIniter::WinsockIniter(): inited_(0){}WinsockIniter::~WinsockIniter(){ if (inited_ && initSuccess_) (void)WSACleanup();}Boolean WinsockIniter::init(Messenger &mgr){ if (!inited_) { inited_ = 1; initSuccess_ = 0; WORD version = MAKEWORD(1, 1); WSADATA wsaData; int err = WSAStartup(version, &wsaData); if (err) mgr.message(URLStorageMessages::winsockInitialize, WinsockMessageArg(err)); else if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { mgr.message(URLStorageMessages::winsockVersion); WSACleanup(); } else initSuccess_ = 1; } return initSuccess_;}#endif /* WINSOCK */#endif /* SP_HAVE_SOCKET */URLStorageManager::URLStorageManager(const char *type): type_(type), IdStorageManager(&iso646Charset){}const char *URLStorageManager::type() const{ return type_;}Boolean URLStorageManager::guessIsId(const StringC &id, const CharsetInfo &charset) const{ if (id.size() < 8) return 0; size_t i = 0; for (const char *s = "http://"; *s; s++, i++) if (id[i] != charset.execToDesc(*s) && (!islower(*s) || id[i] != charset.execToDesc(toupper(*s)))) return 0; return 1;}StorageObject *URLStorageManager::makeStorageObject(const StringC &specId, const StringC &baseId, Boolean, Boolean mayRewind, Messenger &mgr, StringC &id){#ifdef SP_HAVE_SOCKET id = specId; resolveRelative(baseId, id, 0); if (id.size() < 5 || (id[0] != 'h' && id[0] != 'H') || (id[1] != 't' && id[1] != 'T') || (id[2] != 't' && id[2] != 'T') || (id[3] != 'p' && id[3] != 'P') || id[4] != ':') { mgr.message(URLStorageMessages::onlyHTTP); return 0; } if (id.size() < 7 || id[5] != '/' || id[6] != '/') { mgr.message(URLStorageMessages::badRelative, StringMessageArg(id)); return 0; } size_t i = 7; String<char> host; while (i < id.size()) { if (id[i] == '/') break; if (id[i] == ':') break; host += char(id[i]); i++; } if (host.size() == 0) { mgr.message(URLStorageMessages::emptyHost, StringMessageArg(id)); return 0; } unsigned short port; if (i < id.size() && id[i] == ':') { i++; String<char> digits; while (i < id.size() && id[i] != '/') { digits += char(id[i]); i++; } if (digits.size() == 0) { mgr.message(URLStorageMessages::emptyPort, StringMessageArg(id)); return 0; } digits += '\0'; char *endptr; long n = strtol(digits.data(), &endptr, 10); if (endptr != digits.data() + digits.size() - 1 || n < 0 || n > 65535L) { mgr.message(URLStorageMessages::invalidPort, StringMessageArg(id)); return 0; } port = (unsigned short)n; } else port = 80; String<char> path; if (i < id.size()) { while (i < id.size() && id[i] != '#') { path += char(id[i]); i++; } } if (path.size() == 0) path += '/'; StringC hostStr; for (i = 0; i < host.size(); i++) hostStr += host[i]; host += '\0'; SOCKET fd = HttpSocketStorageObject::openHttp(host, port, hostStr, mgr); if (fd == INVALID_SOCKET) return 0; HttpSocketStorageObject *p = new HttpSocketStorageObject(fd, mayRewind, hostStr); if (!p->open(path, mgr)) { delete p; return 0; } return p;#else /* not SP_HAVE_SOCKET */ ParentLocationMessenger(mgr).message(URLStorageMessages::notSupported); return 0;#endif /* not SP_HAVE_SOCKET */}Boolean URLStorageManager::resolveRelative(const StringC &baseId, StringC &id, Boolean) const{ static const char schemeChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "01234567879" "+-."; size_t i; // If it has a scheme, it is absolute. for (i = 0; i < id.size(); i++) { if (id[i] == ':') { if (i == 0) break; else return 1; } else if (!strchr(schemeChars, id[i])) break; } for (i = 0; i < id.size(); i++) { if (id[i] != '/') break; } size_t slashCount = i; if (slashCount > 0) { Boolean foundSameSlash = 0; size_t sameSlashPos; for (size_t j = 0; j < baseId.size(); j++) { size_t thisSlashCount = 0; for (size_t k = j; k < baseId.size() && baseId[k] == '/'; k++) thisSlashCount++; if (thisSlashCount == slashCount && !foundSameSlash) { foundSameSlash = 1; sameSlashPos = j; } else if (thisSlashCount > slashCount) foundSameSlash = 0; } if (foundSameSlash) { StringC tem(baseId.data(), sameSlashPos); tem += id; tem.swap(id); } } else { size_t j; for (j = baseId.size(); j > 0; j--) if (baseId[j - 1] == '/') break; if (j > 0) { StringC tem(baseId.data(), j); tem += id; tem.swap(id); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -