=== added file 'src/gopher.h' --- src/gopher.h 1970-01-01 00:00:00 +0000 +++ src/gopher.h 2006-08-27 23:47:19 +0000 @@ -0,0 +1,109 @@ + +/* + * $Id: $ + * + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#ifndef SQUID_GOPHER_H +#define SQUID_GOPHER_H + +/* we subclass URLScheme */ +#include "forward.h" + +/* This class represents the behaviour of GOPHER urls. + * It does not represent the wire PROTOCOL for gopher. + */ + +class URLSchemeGopher : public URLSchemeForwardable +{ + +public: + URLSchemeGopher(URLSchemeRegistry ®istry): URLSchemeForwardable(®istry, PROTO_VIRTUAL) {} + URLSchemeGopher() : URLSchemeForwardable(PROTO_VIRTUAL) {} + + virtual operator protocol_t() const { return PROTO_VIRTUAL; } + + virtual bool operator != (protocol_t const & aProtocol) const { return PROTO_VIRTUAL != aProtocol;} + + /* Get a char string representation of the scheme. */ + virtual char const *const_str() const { return "gopher"; } + + /* We only support 'GET' and 'HEAD' translated requests. */ + virtual bool canServe(HttpRequest const * request) const; + + /* We can tell from the request whether the gopher request is possibly + * cachable + */ + virtual bool cacheable(HttpRequest const * request) const; + + /* Gopher servers are connected to by the forward module. When it connects + * it calls us back: + */ + virtual void connectedToServer(FwdState * fwdState) const; + + /* gopher runs on port 70 */ + virtual int defaultPort() const; + +// /* XXX functions to add: +// * // return true if this protocol can be revalidated or false if a cache +// * // miss requires a new retrieval every time +// * supportsRevalidate(); +// * // return true if this protocol will fetch remote data +// * fetchesRemoteData(); +// * // a peer has been connected too - start a request on it +// * // only needed for fetchesRemoteData instances. +// * peerConnected(); +// * // format a url for the error page when it had a 2f hack. +// * // probably should be on request +// * formatRequestURLFTPWith2f() +// * // what port is the default port for this scheme ? +// * defaultPort(); +// * // this request was an HTTPS request. Better than a typecode because +// * // a new scheme like TLS may want to claim to be HTTPS in this manner +// * isHTTPS(); +// * // supply a 'direct' peer on request.. WAIS uses a configured peer rather +// * // than using NULL - which forward.cc takes to mean 'do a DNS choice' +// * // because WAIS is not natively spoken by squid and needs a peer to +// * // talk to. +// * getDirectPeer(); +// * +// * +// */ +private: + /* This is a typecode for now - TODO make the varying methods virtual + * Doing that without doubling the storage size will require having + * something like a flyweight. perhaps the strategy pattern is appropiate: + * one strategy per scheme, and an object that is nothing but a pointer + * into the registry of schemes. + */ +}; + + +#endif /* SQUID_GOPHER_H */ === added file 'src/internal.h' --- src/internal.h 1970-01-01 00:00:00 +0000 +++ src/internal.h 2006-08-24 11:32:19 +0000 @@ -0,0 +1,60 @@ + +/* + * $Id: URLScheme.h,v 1.2 2006/05/10 23:40:38 wessels Exp $ + * + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +/* The behaviour for the 'internal:' url scheme. */ + +#ifndef SQUID_URLSCHEMEINTERNAL_H +#define SQUID_URLSCHEMEINTERNAL_H + +#include "URLScheme.h" + +class URLSchemeInternal : public URLScheme +{ + +public: + URLSchemeInternal(); + URLSchemeInternal(URLSchemeRegistry ®istry); + virtual operator protocol_t() const { return PROTO_INTERNAL; } + + virtual bool operator != (protocol_t const & aProtocol) const { return PROTO_INTERNAL != aProtocol;} + + /* Get a char string representation of the scheme. */ + virtual char const *const_str() const { return "internal"; } + + /* start a fetch of the data for a request into a store + * entry. - this replaces internalStart. + */ + virtual void startFetch(HttpRequest * request, StoreEntry * entry, int const client_fd) const; +}; + +#endif /* SQUID_URLSCHEMEINTERNAL_H */ === added file 'src/neighbors.h' --- src/neighbors.h 1970-01-01 00:00:00 +0000 +++ src/neighbors.h 2006-08-26 06:41:39 +0000 @@ -0,0 +1,82 @@ + +/* + * $Id: $ + * + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#ifndef SQUID_NEIGHBORS_H +#define SQUID_NEIGHBORS_H + +/* For the definition of protocol_t */ +#include "URLScheme.h" + +typedef void IRCB(peer *, peer_t, protocol_t, void *, void *data); + +extern peer *getFirstPeer(void); +extern peer *getFirstUpParent(HttpRequest *); +extern peer *getNextPeer(peer *); +extern peer *getSingleParent(HttpRequest *); +extern int neighborsCount(HttpRequest *); +extern int neighborsUdpPing(HttpRequest *, + StoreEntry *, + IRCB * callback, + void *data, + int *exprep, + int *timeout); +extern void neighborAddAcl(const char *, const char *); + +extern void neighborsUdpAck(const cache_key *, icp_common_t *, const struct sockaddr_in *); +extern void neighborAdd(const char *, const char *, int, int, int, int, int); +extern void neighbors_init(void); +extern void neighborsRegisterWithCacheManager(CacheManager & manager); +extern peer *peerFindByName(const char *); +extern peer *peerFindByNameAndPort(const char *, unsigned short); +extern peer *getDefaultParent(HttpRequest * request); +extern peer *getRoundRobinParent(HttpRequest * request); +extern peer *getWeightedRoundRobinParent(HttpRequest * request); +extern void peerClearRR(void *); +extern peer *getAnyParent(HttpRequest * request); +extern lookup_t peerDigestLookup(peer * p, HttpRequest * request); +extern peer *neighborsDigestSelect(HttpRequest * request); +extern void peerNoteDigestLookup(HttpRequest * request, peer * p, lookup_t lookup); +extern void peerNoteDigestGone(peer * p); +extern int neighborUp(const peer * e); +extern CBDUNL peerDestroy; +extern const char *neighborTypeStr(const peer * e); +extern peer_t neighborType(const peer *, const HttpRequest *); +extern void peerConnectFailed(peer *); +extern void peerConnectSucceded(peer *); +extern void dump_peer_options(StoreEntry *, peer *); +extern int peerHTTPOkay(const peer *, HttpRequest *); + +extern peer *whichPeer(const struct sockaddr_in *from); + + +#endif /* SQUID_NEIGHBORS_H */ === added file 'src/tests/testHeader_CacheManager.cc' --- src/tests/testHeader_CacheManager.cc 1970-01-01 00:00:00 +0000 +++ src/tests/testHeader_CacheManager.cc 2006-08-24 05:32:20 +0000 @@ -0,0 +1,4 @@ +/* This test tests that the header below can be processed on its own with + * no other #includes. Dont add any! + */ +#include "CacheManager.h" === added file 'src/tests/testHeader_gopher.cc' --- src/tests/testHeader_gopher.cc 1970-01-01 00:00:00 +0000 +++ src/tests/testHeader_gopher.cc 2006-08-27 01:22:14 +0000 @@ -0,0 +1,4 @@ +/* This test tests that the header below can be processed on its own with + * no other #includes. Dont add any! + */ +#include "gopher.h" === added file 'src/tests/testHeader_internal.cc' --- src/tests/testHeader_internal.cc 1970-01-01 00:00:00 +0000 +++ src/tests/testHeader_internal.cc 2006-08-24 05:21:58 +0000 @@ -0,0 +1,4 @@ +/* This test tests that the header below can be processed on its own with + * no other #includes. Dont add any! + */ +#include "internal.h" === added file 'src/tests/testHeader_neighbors.cc' --- src/tests/testHeader_neighbors.cc 1970-01-01 00:00:00 +0000 +++ src/tests/testHeader_neighbors.cc 2006-08-26 06:37:42 +0000 @@ -0,0 +1,4 @@ +/* This test tests that the header below can be processed on its own with + * no other #includes. Dont add any! + */ +#include "neighbors.h" === added file 'src/tests/testHeader_urn.cc' --- src/tests/testHeader_urn.cc 1970-01-01 00:00:00 +0000 +++ src/tests/testHeader_urn.cc 2006-08-24 05:34:57 +0000 @@ -0,0 +1,4 @@ +/* This test tests that the header below can be processed on its own with + * no other #includes. Dont add any! + */ +#include "urn.h" === added file 'src/tests/testURLSchemeCacheObject.cc' --- src/tests/testURLSchemeCacheObject.cc 1970-01-01 00:00:00 +0000 +++ src/tests/testURLSchemeCacheObject.cc 2006-08-24 06:39:02 +0000 @@ -0,0 +1,89 @@ +#include "squid.h" +#include +#include + +#include "HttpRequest.h" +#include "Mem.h" +#include "testURLSchemeCacheObject.h" +#include "CacheManager.h" + + +CPPUNIT_TEST_SUITE_REGISTRATION( testURLSchemeCacheObject ); + + +/* + * We should be able to get a protocol_t from a URLScheme for ease + * of migration + */ +void +testURLSchemeCacheObject::testCastToprotocol_t() +{ + /* explicit cast */ + protocol_t protocol = (protocol_t) URLSchemeCacheObject(); + CPPUNIT_ASSERT_EQUAL(PROTO_CACHEOBJ, protocol); + /* and implicit */ + protocol = URLSchemeCacheObject(); + CPPUNIT_ASSERT_EQUAL(PROTO_CACHEOBJ, protocol); +} + +/* + * we should be able to get a char const * version of the method. + */ +void +testURLSchemeCacheObject::testConst_str() +{ + CPPUNIT_ASSERT_EQUAL(String("cache_object"), String(URLSchemeCacheObject().const_str())); +} + +/* + * a URLScheme replaces protocol_t, so we should be able to test for equality on + * either the left or right hand side seamlessly. + */ +void +testURLSchemeCacheObject::testEqualprotocol_t() +{ + CPPUNIT_ASSERT(URLSchemeCacheObject() == PROTO_CACHEOBJ); + CPPUNIT_ASSERT(not (URLSchemeCacheObject() == PROTO_NONE)); + CPPUNIT_ASSERT(PROTO_CACHEOBJ == URLSchemeCacheObject()); + CPPUNIT_ASSERT(not (PROTO_NONE == URLSchemeCacheObject())); +} + +/* + * a URLScheme should testable for inequality with a protocol_t. + */ +void +testURLSchemeCacheObject::testNotEqualprotocol_t() +{ + CPPUNIT_ASSERT(URLSchemeCacheObject() != PROTO_NONE); + CPPUNIT_ASSERT(not (URLSchemeCacheObject() != PROTO_CACHEOBJ)); + CPPUNIT_ASSERT(PROTO_NONE != URLSchemeCacheObject()); + CPPUNIT_ASSERT(not (PROTO_CACHEOBJ != URLSchemeCacheObject())); +} + +/* + * The CacheObject URL scheme fetches data by performing + * what cachemgrStart used to do - and is not yet ready to + * be unit tested. + */ +void +testURLSchemeCacheObject::testStartFetch() +{ + URLSchemeCacheObject scheme; + HttpRequest * request = NULL; + StoreEntry * entry = NULL; + int client_fd = -1; + if (0) + scheme.startFetch(request, entry, client_fd); + /* TODO ensure this started a cachemgr lookup */ +} + + +/* the cache_object protocol should be registered + */ +void +testURLSchemeCacheObject::testDefaultsRegistered() +{ + URLSchemeRegistry ®istry(URLSchemeRegistry::GetInstance()); + CPPUNIT_ASSERT_EQUAL(String("cache_object"), + String(registry.findScheme("cache_object")->const_str())); +} === added file 'src/tests/testURLSchemeCacheObject.h' --- src/tests/testURLSchemeCacheObject.h 1970-01-01 00:00:00 +0000 +++ src/tests/testURLSchemeCacheObject.h 2006-08-24 06:20:38 +0000 @@ -0,0 +1,34 @@ + +#ifndef SQUID_SRC_TEST_URL_SCHEME_CACHEOBJECT_H +#define SQUID_SRC_TEST_URL_SCHEME_CACHEOBJECT_H + +#include + +/* + * test URLSchemeCacheObject + */ + +class testURLSchemeCacheObject : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( testURLSchemeCacheObject ); + CPPUNIT_TEST( testCastToprotocol_t ); + CPPUNIT_TEST( testDefaultsRegistered ); + CPPUNIT_TEST( testEqualprotocol_t ); + CPPUNIT_TEST( testNotEqualprotocol_t ); + CPPUNIT_TEST( testConst_str ); + CPPUNIT_TEST( testStartFetch ); + CPPUNIT_TEST_SUITE_END(); + +public: + +protected: + void testCastToprotocol_t(); + void testConst_str(); + void testDefaultsRegistered(); + void testEqualprotocol_t(); + void testNotEqualprotocol_t(); + void testStartFetch(); +}; + +#endif + === added file 'src/tests/testURLSchemeURN.cc' --- src/tests/testURLSchemeURN.cc 1970-01-01 00:00:00 +0000 +++ src/tests/testURLSchemeURN.cc 2006-08-26 07:24:09 +0000 @@ -0,0 +1,124 @@ +#include "squid.h" +#include +#include + +#include "HttpRequest.h" +#include "Mem.h" +#include "testURLSchemeURN.h" +#include "urn.h" + + +CPPUNIT_TEST_SUITE_REGISTRATION( testURLSchemeURN ); + + +/* + * We should be able to get a protocol_t from a URLScheme for ease + * of migration + */ +void +testURLSchemeURN::testCastToprotocol_t() +{ + /* explicit cast */ + protocol_t protocol = (protocol_t) URLSchemeURN(); + CPPUNIT_ASSERT_EQUAL(PROTO_VIRTUAL, protocol); + /* and implicit */ + protocol = URLSchemeURN(); + CPPUNIT_ASSERT_EQUAL(PROTO_VIRTUAL, protocol); +} + +/* + * we should be able to get a char const * version of the method. + */ +void +testURLSchemeURN::testConst_str() +{ + CPPUNIT_ASSERT_EQUAL(String("urn"), String(URLSchemeURN().const_str())); +} + +/* + * a URLScheme replaces protocol_t, so we should be able to test for equality on + * either the left or right hand side seamlessly. + */ +void +testURLSchemeURN::testEqualprotocol_t() +{ + CPPUNIT_ASSERT(URLSchemeURN() == PROTO_VIRTUAL); + CPPUNIT_ASSERT(not (URLSchemeURN() == PROTO_NONE)); + CPPUNIT_ASSERT(PROTO_VIRTUAL == URLSchemeURN()); + CPPUNIT_ASSERT(not (PROTO_NONE == URLSchemeURN())); +} + +/* + * a URLScheme should testable for inequality with a protocol_t. + */ +void +testURLSchemeURN::testNotEqualprotocol_t() +{ + CPPUNIT_ASSERT(URLSchemeURN() != PROTO_NONE); + CPPUNIT_ASSERT(not (URLSchemeURN() != PROTO_VIRTUAL)); + CPPUNIT_ASSERT(PROTO_NONE != URLSchemeURN()); + CPPUNIT_ASSERT(not (PROTO_VIRTUAL != URLSchemeURN())); +} + +/* + * The URN URL scheme fetches data by performing + * what cachemgrStart used to do - and is not yet ready to + * be unit tested. + */ +void +testURLSchemeURN::testStartFetch() +{ + URLSchemeURN scheme; + HttpRequest * request = NULL; + StoreEntry * entry = NULL; + int client_fd = -1; + if (0) + scheme.startFetch(request, entry, client_fd); + /* TODO ensure this started a cachemgr lookup */ +} + + +/* the urn schem should be registered + */ +void +testURLSchemeURN::testDefaultsRegistered() +{ + URLSchemeRegistry ®istry(URLSchemeRegistry::GetInstance()); + CPPUNIT_ASSERT_EQUAL(String("urn"), + String(registry.findScheme("urn")->const_str())); +} + +/* + * the urn canonical scheme gives you the HttpRequest-> urlpath preprended by + * urn: + */ +void +testURLSchemeURN::testCanonicalUrl() +{ + URLSchemeURN scheme; + HttpRequest request(METHOD_GET, &scheme, "foo-bar-baz"); + CPPUNIT_ASSERT_EQUAL(String("urn:foo-bar-baz"), scheme.canonicalUrl(&request)); +} + +/* + * the urn canonical scheme gives you the HttpRequest-> urlpath preprended by + * urn: + */ +void +testURLSchemeURN::testCanonicalUrlCleanUncleaned() +{ + URLSchemeURN scheme; + HttpRequest request(METHOD_GET, &scheme, "foo-bar-baz\x1e"); + CPPUNIT_ASSERT_EQUAL(String("urn:foo-bar-baz\x1e"), scheme.canonicalUrlCleanUncleaned(&request)); +} + +/* + * Test the request flavours that we handle for URN's. Currently this is defined + * as 'anything', which may or may not be bogus. + */ +void +testURLSchemeURN::testCanServe() +{ + URLSchemeURN scheme; + CPPUNIT_ASSERT_EQUAL(true, scheme.canServe(NULL)); +} === added file 'src/tests/testURLSchemeURN.h' --- src/tests/testURLSchemeURN.h 1970-01-01 00:00:00 +0000 +++ src/tests/testURLSchemeURN.h 2006-08-26 03:16:47 +0000 @@ -0,0 +1,40 @@ + +#ifndef SQUID_SRC_TEST_URL_SCHEME_URN_H +#define SQUID_SRC_TEST_URL_SCHEME_URN_H + +#include + +/* + * test URLSchemeURN + */ + +class testURLSchemeURN : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( testURLSchemeURN ); + CPPUNIT_TEST( testCanServe ); + CPPUNIT_TEST( testCanonicalUrl ); + CPPUNIT_TEST( testCanonicalUrlCleanUncleaned ); + CPPUNIT_TEST( testCastToprotocol_t ); + CPPUNIT_TEST( testDefaultsRegistered ); + CPPUNIT_TEST( testEqualprotocol_t ); + CPPUNIT_TEST( testNotEqualprotocol_t ); + CPPUNIT_TEST( testConst_str ); + CPPUNIT_TEST( testStartFetch ); + CPPUNIT_TEST_SUITE_END(); + +public: + +protected: + void testCanServe(); + void testCanonicalUrl(); + void testCanonicalUrlCleanUncleaned(); + void testCastToprotocol_t(); + void testConst_str(); + void testDefaultsRegistered(); + void testEqualprotocol_t(); + void testNotEqualprotocol_t(); + void testStartFetch(); +}; + +#endif + === added file 'src/tests/testgopher.cc' --- src/tests/testgopher.cc 1970-01-01 00:00:00 +0000 +++ src/tests/testgopher.cc 2006-08-27 23:48:35 +0000 @@ -0,0 +1,116 @@ +#include "squid.h" +#include +#include + +#include "HttpRequest.h" +#include "Mem.h" +#include "testgopher.h" +#include "gopher.h" + + +CPPUNIT_TEST_SUITE_REGISTRATION( testURLSchemeGopher ); + +/* GOPHER uses the new PROTOCOL_VIRTUAL enum value */ +void +testURLSchemeGopher::testCastToprotocol_t() +{ + /* explicit cast */ + protocol_t protocol = (protocol_t) URLSchemeGopher(); + CPPUNIT_ASSERT_EQUAL(PROTO_VIRTUAL, protocol); + /* and implicit */ + protocol = URLSchemeGopher(); + CPPUNIT_ASSERT_EQUAL(PROTO_VIRTUAL, protocol); +} + +/* whats the protocol string ? */ +void +testURLSchemeGopher::testConst_str() +{ + CPPUNIT_ASSERT_EQUAL(String("gopher"), String(URLSchemeGopher().const_str())); +} + +/* GOPHER uses the new PROTOCOL_VIRTUAL enum value */ +void +testURLSchemeGopher::testEqualprotocol_t() +{ + CPPUNIT_ASSERT(URLSchemeGopher() == PROTO_VIRTUAL); + CPPUNIT_ASSERT(not (URLSchemeGopher() == PROTO_NONE)); + CPPUNIT_ASSERT(PROTO_VIRTUAL == URLSchemeGopher()); + CPPUNIT_ASSERT(not (PROTO_NONE == URLSchemeGopher())); +} + +/* GOPHER uses the new PROTOCOL_VIRTUAL enum value */ +void +testURLSchemeGopher::testNotEqualprotocol_t() +{ + CPPUNIT_ASSERT(URLSchemeGopher() != PROTO_NONE); + CPPUNIT_ASSERT(not (URLSchemeGopher() != PROTO_VIRTUAL)); + CPPUNIT_ASSERT(PROTO_NONE != URLSchemeGopher()); + CPPUNIT_ASSERT(not (PROTO_VIRTUAL != URLSchemeGopher())); +} + +/* + * For gopher, we support GET and HEAD requests only + */ +void +testURLSchemeGopher::testCanServe() +{ + URLSchemeGopher scheme; + HttpRequest get_request(METHOD_GET, &scheme, "foo/bar"); + CPPUNIT_ASSERT_EQUAL(true, scheme.canServe(&get_request)); + HttpRequest head_request(METHOD_HEAD, &scheme, "foo/bar"); + CPPUNIT_ASSERT_EQUAL(true, scheme.canServe(&head_request)); + HttpRequest put_request(METHOD_PUT, &scheme, "foo/bar"); + CPPUNIT_ASSERT_EQUAL(false, scheme.canServe(&put_request)); + /* we could test every known method, but theres a limit to sanity for + * such a short method + */ +} + +/* + * Gopher requests are cachable except for INDEX, CSO, TELNET and 3270 + */ +void +testURLSchemeGopher::testCacheable() +{ + URLSchemeGopher scheme; + HttpRequest dir_request(METHOD_GET, &scheme, ""); + CPPUNIT_ASSERT_EQUAL(true, scheme.cacheable(&dir_request)); + HttpRequest index_request(METHOD_GET, &scheme, "7"); + CPPUNIT_ASSERT_EQUAL(false, scheme.cacheable(&index_request)); + HttpRequest cso_request(METHOD_GET, &scheme, "2"); + CPPUNIT_ASSERT_EQUAL(false, scheme.cacheable(&cso_request)); + HttpRequest telnet_request(METHOD_GET, &scheme, "8"); + CPPUNIT_ASSERT_EQUAL(false, scheme.cacheable(&telnet_request)); + HttpRequest thirty270_request(METHOD_GET, &scheme, "T"); + CPPUNIT_ASSERT_EQUAL(false, scheme.cacheable(&thirty270_request)); +} + +/* + * When we connect to the server we should send a gopher request to it. + * At the moment the test infrastructure to validate this is lacking, + * so we just make sure the API call compiles. + */ +void +testURLSchemeGopher::testConnectedToServer() +{ + URLSchemeGopher scheme; + if (0) scheme.connectedToServer(NULL); +} + +/* The gopher protocol is on port 70 */ +void +testURLSchemeGopher::testDefaultPort() +{ + URLSchemeGopher scheme; + CPPUNIT_ASSERT_EQUAL(70, scheme.defaultPort()); +} + +/* the gopher: scheme should be registered */ +void +testURLSchemeGopher::testDefaultsRegistered() +{ + URLSchemeRegistry ®istry(URLSchemeRegistry::GetInstance()); + CPPUNIT_ASSERT_EQUAL(String("gopher"), + String(registry.findScheme("gopher")->const_str())); +} === added file 'src/tests/testgopher.h' --- src/tests/testgopher.h 1970-01-01 00:00:00 +0000 +++ src/tests/testgopher.h 2006-08-27 23:30:19 +0000 @@ -0,0 +1,40 @@ + +#ifndef SQUID_SRC_TEST_GOPHER_H +#define SQUID_SRC_TEST_GOPHER_H + +#include + +/* + * test URLSchemeGopher + */ + +class testURLSchemeGopher : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( testURLSchemeGopher ); + CPPUNIT_TEST( testCacheable ); + CPPUNIT_TEST( testCastToprotocol_t ); + CPPUNIT_TEST( testCanServe ); + CPPUNIT_TEST( testConnectedToServer ); + CPPUNIT_TEST( testConst_str ); + CPPUNIT_TEST( testDefaultPort ); + CPPUNIT_TEST( testDefaultsRegistered ); + CPPUNIT_TEST( testEqualprotocol_t ); + CPPUNIT_TEST( testNotEqualprotocol_t ); + CPPUNIT_TEST_SUITE_END(); + +public: + +protected: + void testCacheable(); + void testCastToprotocol_t(); + void testCanServe(); + void testConnectedToServer(); + void testConst_str(); + void testDefaultPort(); + void testDefaultsRegistered(); + void testEqualprotocol_t(); + void testNotEqualprotocol_t(); +}; + +#endif + === added file 'src/tests/testinternal.cc' --- src/tests/testinternal.cc 1970-01-01 00:00:00 +0000 +++ src/tests/testinternal.cc 2006-08-24 06:28:47 +0000 @@ -0,0 +1,90 @@ +#include "squid.h" +#include +#include + +#include "HttpRequest.h" +#include "Mem.h" +#include "testinternal.h" +#include "internal.h" + + +CPPUNIT_TEST_SUITE_REGISTRATION( testInternal ); + + +/* + * We should be able to get a protocol_t from a URLScheme for ease + * of migration + */ +void +testInternal::testCastToprotocol_t() +{ + /* explicit cast */ + protocol_t protocol = (protocol_t) URLSchemeInternal(); + CPPUNIT_ASSERT_EQUAL(PROTO_INTERNAL, protocol); + /* and implicit */ + protocol = URLSchemeInternal(); + CPPUNIT_ASSERT_EQUAL(PROTO_INTERNAL, protocol); +} + +/* + * we should be able to get a char const * version of the method. + */ +void +testInternal::testConst_str() +{ + CPPUNIT_ASSERT_EQUAL(String("internal"), String(URLSchemeInternal().const_str())); +} + +/* + * a URLSchemeInternal replaces protocol_t, so we should be able to test for equality on + * either the left or right hand side seamlessly. + */ +void +testInternal::testEqualprotocol_t() +{ + CPPUNIT_ASSERT(URLSchemeInternal() == PROTO_INTERNAL); + CPPUNIT_ASSERT(not (URLSchemeInternal() == PROTO_NONE)); + CPPUNIT_ASSERT(PROTO_INTERNAL == URLSchemeInternal()); + CPPUNIT_ASSERT(not (PROTO_NONE == URLSchemeInternal())); +} + +/* + * a URLSchemeInternal should testable for inequality with a protocol_t. + */ +void +testInternal::testNotEqualprotocol_t() +{ + CPPUNIT_ASSERT(URLSchemeInternal() != PROTO_NONE); + CPPUNIT_ASSERT(not (URLSchemeInternal() != PROTO_INTERNAL)); + CPPUNIT_ASSERT(PROTO_NONE != URLSchemeInternal()); + CPPUNIT_ASSERT(not (PROTO_INTERNAL != URLSchemeInternal())); +} + +/* The internal URL scheme fetches data by performing what + * internalStart used to do - and which is not yet ready to + * be unit tested. + */ +void +testInternal::testStartFetch() +{ + URLSchemeInternal scheme; + HttpRequest * request = NULL; + StoreEntry * entry = NULL; + int client_fd = -1; + if (0) + scheme.startFetch(request, entry, client_fd); + /* TODO: ensure this went through the internal request + * codepath + */ +} + + +/* the internal protocol should be registered + */ +void +testInternal::testDefaultsRegistered() +{ + URLSchemeRegistry ®istry(URLSchemeRegistry::GetInstance()); + CPPUNIT_ASSERT_EQUAL(String("internal"), + String(registry.findScheme("internal")->const_str())); +} === added file 'src/tests/testinternal.h' --- src/tests/testinternal.h 1970-01-01 00:00:00 +0000 +++ src/tests/testinternal.h 2006-08-24 05:29:55 +0000 @@ -0,0 +1,34 @@ + +#ifndef SQUID_SRC_TEST_INTERNAL_H +#define SQUID_SRC_TEST_INTERNAL_H + +#include + +/* + * test internal urls. + */ + +class testInternal : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( testInternal ); + CPPUNIT_TEST( testCastToprotocol_t ); + CPPUNIT_TEST( testDefaultsRegistered ); + CPPUNIT_TEST( testEqualprotocol_t ); + CPPUNIT_TEST( testNotEqualprotocol_t ); + CPPUNIT_TEST( testConst_str ); + CPPUNIT_TEST( testStartFetch ); + CPPUNIT_TEST_SUITE_END(); + +public: + +protected: + void testCastToprotocol_t(); + void testConst_str(); + void testDefaultsRegistered(); + void testEqualprotocol_t(); + void testNotEqualprotocol_t(); + void testStartFetch(); +}; + +#endif + === added file 'src/urn.h' --- src/urn.h 1970-01-01 00:00:00 +0000 +++ src/urn.h 2006-08-26 08:20:50 +0000 @@ -0,0 +1,64 @@ + +/* + * $Id: URLScheme.h,v 1.2 2006/05/10 23:40:38 wessels Exp $ + * + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +/* The behaviour for the 'internal:' url scheme. */ + +#ifndef SQUID_URN_H +#define SQUID_URN_H + +#include "URLScheme.h" + +class URLSchemeURN : public URLScheme +{ + +public: + URLSchemeURN(); + URLSchemeURN(URLSchemeRegistry &); + virtual operator protocol_t() const { return PROTO_VIRTUAL; } + + virtual bool operator != (protocol_t const & aProtocol) const { return PROTO_VIRTUAL != aProtocol;} + + /* Get a char string representation of the scheme. */ + virtual char const *const_str() const { return "urn"; } + + /* start a fetch of the data for a request into a store entry. */ + virtual void startFetch(HttpRequest * request, StoreEntry * entry, int const client_fd) const; + + /* URN URLs are not hierarchical URL's. */ + virtual String canonicalUrl(HttpRequest const * request) const; + virtual String canonicalUrlCleanUncleaned(HttpRequest const * request) const; + /* Define the rules for URN request handling - post etc */ + virtual bool canServe(HttpRequest const * request) const; +}; + +#endif /* SQUID_URN_H */ === modified file 'configure.in' --- configure.in 2006-08-21 00:43:11 +0000 +++ configure.in 2006-08-28 00:07:49 +0000 @@ -696,6 +696,25 @@ AC_SUBST(REPL_OBJS) AC_SUBST(REPL_LIBS) +###### PROTOCOLS ######## +AM_CONDITIONAL(ENABLE_GOPHER_SUPPORT, false) +AC_ARG_ENABLE(gopher, +[ --enable-gopher Enable the Gopher gateway], +[ if test "$enableval" = "yes" ; then + echo "Gopher gateway enabled" + AM_CONDITIONAL(ENABLE_GOPHER_SUPPORT, true) + fi +]) + +AM_CONDITIONAL(ENABLE_URN_SUPPORT, false) +AC_ARG_ENABLE(urn, +[ --enable-urn Enable URN resolution support], +[ if test "$enableval" = "yes" ; then + echo "URN enabled" + AM_CONDITIONAL(ENABLE_URN_SUPPORT, true) + fi +]) + AM_CONDITIONAL(ENABLE_PINGER, false) AC_ARG_ENABLE(icmp, [ --enable-icmp Enable ICMP pinging], === modified file 'src/ACLProtocol.cc' --- src/ACLProtocol.cc 2006-04-23 09:59:25 +0000 +++ src/ACLProtocol.cc 2006-08-24 02:42:54 +0000 @@ -41,18 +41,18 @@ /* explicit template instantiation required for some systems */ -template class ACLStrategised +template class ACLStrategised ; ACL::Prototype ACLProtocol::RegistryProtoype(&ACLProtocol::RegistryEntry_, "proto"); -ACLStrategised ACLProtocol::RegistryEntry_(new ACLProtocolData, ACLProtocolStrategy::Instance(), "proto"); +ACLStrategised ACLProtocol::RegistryEntry_(new ACLProtocolData, ACLProtocolStrategy::Instance(), "proto"); int ACLProtocolStrategy::match (ACLData * &data, ACLChecklist *checklist) { - return data->match (checklist->request->protocol); + return data->match (checklist->request->scheme); ; } === modified file 'src/ACLProtocol.h' --- src/ACLProtocol.h 2006-04-23 09:59:25 +0000 +++ src/ACLProtocol.h 2006-08-24 02:43:19 +0000 @@ -37,8 +37,9 @@ #define SQUID_ACLPROTOCOL_H #include "ACLStrategy.h" #include "ACLStrategised.h" +#include "URLScheme.h" -class ACLProtocolStrategy : public ACLStrategy +class ACLProtocolStrategy : public ACLStrategy { public: @@ -63,7 +64,7 @@ private: static ACL::Prototype RegistryProtoype; - static ACLStrategised RegistryEntry_; + static ACLStrategised RegistryEntry_; }; #endif /* SQUID_ACLPROTOCOL_H */ === modified file 'src/ACLProtocolData.cc' --- src/ACLProtocolData.cc 2006-05-08 22:48:34 +0000 +++ src/ACLProtocolData.cc 2006-08-26 05:00:24 +0000 @@ -55,24 +55,24 @@ } bool -ACLProtocolData::match(protocol_t toFind) +ACLProtocolData::match(URLScheme const * toFind) { return values->findAndTune (toFind); } /* explicit instantiation required for some systems */ -template cbdata_type List +template cbdata_type List ::CBDATA_List; wordlist * ACLProtocolData::dump() { wordlist *W = NULL; - List *data = values; + List *data = values; while (data != NULL) { - wordlistAdd(&W, ProtocolStr[data->element]); + wordlistAdd(&W, data->element->const_str()); data = data->next; } @@ -82,14 +82,15 @@ void ACLProtocolData::parse() { - List **Tail; + List **Tail; char *t = NULL; for (Tail = &values; *Tail; Tail = &((*Tail)->next)) ; while ((t = strtokFile())) { - List *q = new List (urlParseProtocol(t)); + List *q = new List ( + URLSchemeRegistry::GetInstance().findScheme(t)); *(Tail) = q; Tail = &q->next; } @@ -101,7 +102,7 @@ return values == NULL; } -ACLData * +ACLData * ACLProtocolData::clone() const { /* Splay trees don't clone yet. */ === modified file 'src/ACLProtocolData.h' --- src/ACLProtocolData.h 2006-04-23 09:59:25 +0000 +++ src/ACLProtocolData.h 2006-08-24 02:49:25 +0000 @@ -39,7 +39,9 @@ #include "ACLData.h" #include "List.h" -class ACLProtocolData : public ACLData +class URLScheme; + +class ACLProtocolData : public ACLData { public: @@ -49,13 +51,13 @@ ACLProtocolData(ACLProtocolData const &); ACLProtocolData &operator= (ACLProtocolData const &); virtual ~ACLProtocolData(); - bool match(protocol_t); + bool match(URLScheme const *); wordlist *dump(); void parse(); bool empty() const; - virtual ACLData *clone() const; + virtual ACLData *clone() const; - List *values; + List *values; }; MEMPROXY_CLASS_INLINE(ACLProtocolData); === modified file 'src/CacheManager.h' --- src/CacheManager.h 2006-05-29 00:16:05 +0000 +++ src/CacheManager.h 2006-08-24 11:38:46 +0000 @@ -35,9 +35,8 @@ #define SQUID_CACHEMANAGER_H #include "squid.h" - - -extern void cachemgrStart(int fd, HttpRequest * request, StoreEntry * entry); +#include "URLScheme.h" + /* * A single menu item in the cache manager - an 'action'. @@ -91,4 +90,22 @@ virtual CacheManagerAction * findAction(char const * action); }; + +/* scheme object to support requesting mgr: urls. */ +class URLSchemeCacheObject : public URLScheme +{ +public: + URLSchemeCacheObject(); + URLSchemeCacheObject(URLSchemeRegistry ®istry); + virtual operator protocol_t() const { return PROTO_CACHEOBJ; } + + virtual bool operator != (protocol_t const & aProtocol) const { return PROTO_CACHEOBJ != aProtocol;} + + /* Get a char string representation of the scheme. */ + virtual char const *const_str() const { return "cache_object"; } + + /* start a fetch of the data for a request into a store entry. */ + virtual void startFetch(HttpRequest * request, StoreEntry * entry, int const client_fd) const; +}; + #endif /* SQUID_CACHEMANAGER_H */ === modified file 'src/HttpMsg.cc' --- src/HttpMsg.cc 2006-05-27 00:31:17 +0000 +++ src/HttpMsg.cc 2006-08-24 02:56:05 +0000 @@ -38,7 +38,7 @@ #include "MemBuf.h" HttpMsg::HttpMsg(http_hdr_owner_type owner): header(owner), - cache_control(NULL), hdr_sz(0), content_length(0), protocol(PROTO_NONE), + cache_control(NULL), hdr_sz(0), content_length(0), pstate(psReadyToParseStartLine), lock_count(0) {} === modified file 'src/HttpMsg.h' --- src/HttpMsg.h 2006-04-23 09:59:25 +0000 +++ src/HttpMsg.h 2006-08-24 02:53:37 +0000 @@ -38,6 +38,7 @@ #include "HttpHeader.h" #include "HttpVersion.h" +class URLScheme; // common parts of HttpRequest and HttpReply class HttpMsg @@ -68,8 +69,6 @@ int content_length; - protocol_t protocol; - HttpMsgParseState pstate; /* the current parsing state */ // returns true and sets hdr_sz on success === modified file 'src/HttpRequest.cc' --- src/HttpRequest.cc 2006-05-29 09:16:46 +0000 +++ src/HttpRequest.cc 2006-08-27 23:46:32 +0000 @@ -40,16 +40,17 @@ #include "HttpHeaderRange.h" #include "MemBuf.h" #include "Store.h" +#include "URLScheme.h" -HttpRequest::HttpRequest() : HttpMsg(hoRequest) +HttpRequest::HttpRequest() : HttpMsg(hoRequest), scheme(NULL) { init(); } -HttpRequest::HttpRequest(method_t aMethod, protocol_t aProtocol, const char *aUrlpath) : HttpMsg(hoRequest) +HttpRequest::HttpRequest(method_t aMethod, URLScheme const * aScheme, const char *aUrlpath) : HttpMsg(hoRequest), scheme(URLSchemeRegistry::GetInstance().findScheme("NONE")) { init(); - initHTTP(aMethod, aProtocol, aUrlpath); + initHTTP(aMethod, aScheme, aUrlpath); } HttpRequest::~HttpRequest() @@ -58,10 +59,10 @@ } void -HttpRequest::initHTTP(method_t aMethod, protocol_t aProtocol, const char *aUrlpath) +HttpRequest::initHTTP(method_t aMethod, URLScheme const * aScheme, const char *aUrlpath) { method = aMethod; - protocol = aProtocol; + scheme = aScheme; urlpath = aUrlpath; } @@ -69,7 +70,7 @@ HttpRequest::init() { method = METHOD_NONE; - protocol = PROTO_NONE; + scheme = URLSchemeRegistry::GetInstance().findScheme("NONE"); urlpath = NULL; login[0] = '\0'; host[0] = '\0'; @@ -419,13 +420,13 @@ bool HttpRequest::cacheable() const { - if (protocol == PROTO_HTTP) + if ((protocol_t)(*scheme) == PROTO_HTTP) return httpCachable(method); /* FTP is always cachable */ /* WAIS is never cachable */ - if (protocol == PROTO_WAIS) + if ((protocol_t)(*scheme) == PROTO_WAIS) return 0; /* @@ -441,18 +442,25 @@ if (method == METHOD_PUT) return 0; - if (method == METHOD_POST) - return 0; - /* * XXX POST may be cached sometimes.. ignored * for now */ - if (protocol == PROTO_GOPHER) - return gopherCachable(this); - - if (protocol == PROTO_CACHEOBJ) + if (method == METHOD_POST) + return 0; + + if ((protocol_t)(*scheme) == PROTO_VIRTUAL) + return scheme->cacheable(this); + + if ((protocol_t)(*scheme) == PROTO_CACHEOBJ) return 0; return 1; } + +/* start fetching the data to deliver this request to entry */ +void +HttpRequest::startFetch(StoreEntry *entry, int client_fd) +{ + scheme->startFetch(this, entry, client_fd); +} === modified file 'src/HttpRequest.h' --- src/HttpRequest.h 2006-05-29 09:16:46 +0000 +++ src/HttpRequest.h 2006-08-24 02:53:48 +0000 @@ -55,6 +55,7 @@ MEMPROXY_CLASS(HttpRequest); HttpRequest(); HttpRequest(method_t aMethod, protocol_t aProtocol, const char *aUrlpath); + HttpRequest(method_t aMethod, URLScheme const *aScheme, const char *aUrlpath); ~HttpRequest(); virtual void reset(); @@ -64,11 +65,14 @@ return static_cast(HttpMsg::_lock()); }; - void initHTTP(method_t aMethod, protocol_t aProtocol, const char *aUrlpath); + void initHTTP(method_t aMethod, URLScheme const * aScheme, const char *aUrlpath); /* are responses to this request potentially cachable */ bool cacheable() const; + /* start fetching the data to deliver this request to entry */ + void startFetch(StoreEntry *entry, int client_fd); + protected: void clean(); @@ -77,6 +81,9 @@ public: method_t method; + /* the URL scheme for this request, not related to how we satisfy it */ + URLScheme const *scheme; + char login[MAX_LOGIN_SZ]; char host[SQUIDHOSTNAMELEN + 1]; === modified file 'src/Makefile.am' --- src/Makefile.am 2006-08-21 00:32:38 +0000 +++ src/Makefile.am 2006-08-28 00:09:13 +0000 @@ -161,6 +161,41 @@ ARP_ACL_SOURCE = endif +## PROTOCOLS ## + +GOPHER_PROTOCOL_SOURCE = gopher.cc gopher.h +GOPHER_ALL_TEST_SOURCE = \ + tests/testgopher.cc \ + tests/testgopher.h +GOPHER_ALL_SOURCE = \ + $(GOPHER_PROTOCOL_SOURCE) \ + $(GOPHER_ALL_TEST_SOURCE) +if ENABLE_GOPHER_SUPPORT +GOPHERSOURCE = $(GOPHER_PROTOCOL_SOURCE) +GOPHER_TEST_SOURCE = $(GOPHER_ALL_TEST_SOURCE) +else +GOPHERSOURCE = +GOPHER_TEST_SOURCE = +endif + +URN_PROTOCOL_SOURCE = urn.cc urn.h +URN_ALL_TEST_SOURCE = \ + tests/testURLSchemeURN.cc \ + tests/testURLSchemeURN.h +URN_ALL_SOURCE = \ + $(URN_PROTOCOL_SOURCE) \ + $(URN_ALL_TEST_SOURCE) +if ENABLE_URN_SUPPORT +URNSOURCE = $(URN_PROTOCOL_SOURCE) +URN_TEST_SOURCE = $(URN_ALL_TEST_SOURCE) +else +URNSOURCE = +URN_TEST_SOURCE = +endif + +## END PROTOCOLS ## + + AM_CFLAGS = @SQUID_CFLAGS@ AM_CXXFLAGS = @SQUID_CXXFLAGS@ @@ -240,6 +275,7 @@ auth/negotiate/negotiateScheme.cc \ auth/negotiate/negotiateScheme.h + EXTRA_squid_SOURCES = \ $(all_FSMODULES) \ $(all_DISKIOMODULES) \ @@ -258,6 +294,7 @@ LeakFinder.cc \ LeakFinder.h \ $(SNMP_ALL_SOURCE) \ + $(URN_ALL_SOURCE) \ unlinkd.cc \ $(SSL_ALL_SOURCE) \ $(WIN32_ALL_SOURCE) @@ -352,7 +389,6 @@ comm_kqueue.cc \ comm_kqueue.h - # common library for all the binaries and tests. This is kindof a catch all # and smaller libraries split from this are encouraged. Using lt convenience # libraries, dependencies should not be a problem either. @@ -443,7 +479,6 @@ ftp.cc \ Generic.h \ globals.h \ - gopher.cc \ helper.cc \ helper.h \ HierarchyLogEntry.h \ @@ -482,6 +517,7 @@ $(IDENT_SOURCE) \ int.cc \ internal.cc \ + internal.h \ ipc.cc \ ipcache.cc \ $(LEAKFINDERSOURCE) \ @@ -574,7 +610,8 @@ URL.h \ URLScheme.cc \ URLScheme.h \ - urn.cc \ + $(GOPHERSOURCE) \ + $(URNSOURCE) \ useragent.cc \ wais.cc \ wccp.cc \ @@ -756,7 +793,6 @@ forward.h \ fqdncache.cc \ ftp.cc \ - gopher.cc \ helper.cc \ $(HTCPSOURCE) \ http.cc \ @@ -832,7 +868,6 @@ typedefs.h \ $(UNLINKDSOURCE) \ URLScheme.cc \ - urn.cc \ useragent.cc \ wais.cc \ wccp.cc \ @@ -1207,6 +1242,8 @@ String.cc \ tests/testCacheManager.cc \ tests/testCacheManager.h \ + tests/testURLSchemeCacheObject.cc \ + tests/testURLSchemeCacheObject.h \ tests/testMain.cc \ time.cc \ access_log.cc \ @@ -1246,7 +1283,6 @@ forward.cc \ fqdncache.cc \ ftp.cc \ - gopher.cc \ helper.cc \ $(HTCPSOURCE) \ http.cc \ @@ -1318,7 +1354,6 @@ SwapDir.cc \ url.cc \ URLScheme.cc \ - urn.cc \ useragent.cc \ wais.cc \ wccp2.cc \ @@ -1397,7 +1432,6 @@ forward.cc \ fqdncache.cc \ ftp.cc \ - gopher.cc \ helper.cc \ $(HTCPSOURCE) \ http.cc \ @@ -1468,7 +1502,6 @@ SwapDir.cc \ url.cc \ URLScheme.cc \ - urn.cc \ useragent.cc \ wais.cc \ wccp2.cc \ @@ -1547,7 +1580,6 @@ forward.cc \ fqdncache.cc \ ftp.cc \ - gopher.cc \ helper.cc \ $(HTCPSOURCE) \ http.cc \ @@ -1618,7 +1650,6 @@ SwapDir.cc \ url.cc \ URLScheme.cc \ - urn.cc \ useragent.cc \ wais.cc \ wccp2.cc \ @@ -1654,6 +1685,7 @@ HEADERS_TO_TEST = \ tests/testHeader_ACL.cc \ tests/testHeader_AsyncEngine.cc \ + tests/testHeader_CacheManager.cc \ tests/testHeader_cbdata.cc \ tests/testHeader_CompletionDispatcher.cc \ tests/testHeader_ConfigParser.cc \ @@ -1663,16 +1695,20 @@ tests/testHeader_errorpage.cc \ tests/testHeader_event.cc \ tests/testHeader_EventLoop.cc \ + tests/testHeader_gopher.cc \ tests/testHeader_HttpHeader.cc \ tests/testHeader_HttpHeaderRange.cc \ tests/testHeader_HttpReply.cc \ tests/testHeader_HttpRequestMethod.cc \ + tests/testHeader_internal.cc \ + tests/testHeader_neighbors.cc \ tests/testHeader_RemovalPolicy.cc \ tests/testHeader_SquidTime.cc \ tests/testHeader_Store.cc \ tests/testHeader_StoreEntryStream.cc \ tests/testHeader_URL.cc \ tests/testHeader_URLScheme.cc \ + tests/testHeader_urn.cc \ tests/testHeader_wordlist.cc tests_testHeaders_SOURCES= tests/testMain.cc $(HEADERS_TO_TEST) tests_testHeaders_LDADD= \ @@ -1723,7 +1759,6 @@ fqdncache.cc \ ftp.cc \ globals.cc \ - gopher.cc \ helper.cc \ $(HTCPSOURCE) \ http.cc \ @@ -1798,7 +1833,6 @@ tunnel.cc \ url.cc \ URLScheme.cc \ - urn.cc \ useragent.cc \ wais.cc \ wccp2.cc \ @@ -1874,7 +1908,6 @@ forward.cc \ fqdncache.cc \ ftp.cc \ - gopher.cc \ helper.cc \ $(HTCPSOURCE) \ http.cc \ @@ -1946,7 +1979,6 @@ SwapDir.cc \ url.cc \ URLScheme.cc \ - urn.cc \ useragent.cc \ wais.cc \ wccp2.cc \ @@ -2167,6 +2199,12 @@ tests/testURL.h \ tests/testURLScheme.cc \ tests/testURLScheme.h \ + tests/testinternal.cc \ + tests/testinternal.h \ + $(GOPHER_TEST_SOURCE) \ + $(GOPHERSOURCE) \ + $(URN_TEST_SOURCE) \ + $(URNSOURCE) \ tests/testMain.cc \ time.cc \ access_log.cc \ @@ -2206,7 +2244,6 @@ forward.cc \ fqdncache.cc \ ftp.cc \ - gopher.cc \ helper.cc \ $(HTCPSOURCE) \ http.cc \ @@ -2275,7 +2312,6 @@ tools.cc \ tunnel.cc \ SwapDir.cc \ - urn.cc \ useragent.cc \ wais.cc \ wccp2.cc \ === modified file 'src/MemObject.h' --- src/MemObject.h 2006-08-21 00:32:38 +0000 +++ src/MemObject.h 2006-08-26 06:42:37 +0000 @@ -39,6 +39,8 @@ #include "stmem.h" #include "CommRead.h" #include "RemovalPolicy.h" +/* For IRCB */ +#include "neighbors.h" typedef void STMCB (void *data, StoreIOBuffer wroteBuffer); === modified file 'src/URL.h' --- src/URL.h 2006-05-08 23:58:04 +0000 +++ src/URL.h 2006-08-24 10:19:58 +0000 @@ -46,9 +46,8 @@ public: MEMPROXY_CLASS(URL); - URL(); URL(URLScheme const &); - URLScheme const & getScheme() const {return scheme; } + URLScheme const & getScheme() const {return *scheme; } private: /* the scheme of this URL. This has the 'type code' smell about it. @@ -67,7 +66,7 @@ * In order to make taking any of these routes easy, scheme is private * and immutable, only settable at construction time, */ - URLScheme const scheme; + URLScheme const * scheme; }; MEMPROXY_CLASS_INLINE(URL); === modified file 'src/URLScheme.cc' --- src/URLScheme.cc 2006-05-08 23:58:04 +0000 +++ src/URLScheme.cc 2006-08-28 00:19:41 +0000 @@ -35,24 +35,285 @@ #include "squid.h" #include "URLScheme.h" -#include "wordlist.h" +/* for the definition of HttpRequest, for canonicalURL's default implementation */ +#include "HttpRequest.h" const char *ProtocolStr[] = { "NONE", "http", "ftp", - "gopher", "wais", "cache_object", "icp", #if USE_HTCP "htcp", #endif - "urn", "whois", "internal", "https", + "BAD PROTOCOL", + "VIRTUAL PROTOCOL", "TOTAL" }; +URLSchemeRegistry & +URLSchemeRegistry::GetInstance() +{ + static URLSchemeRegistry _instance; + /* not safe if schemes start deregistering on destruction - + * we'll need either a heap instance here, or the full magic to do a singleton + */ + return _instance; +} + +void +URLSchemeRegistry::registerScheme(URLScheme const *scheme) +{ + schemes.push_back(scheme); +} + +/* parse a string to find an exact scheme match: + * + * if end is NULL, then start is assumed to be \0 terminated and end is + * set to the first : in start. Its faster + * to supply end when it is available. + */ +URLScheme const * +URLSchemeRegistry::findScheme(char const *start, char const * end) +{ + URLScheme const * fallback = NULL; + + /* + * if end is NULL, start must be \0 terminated and we + * make end point to the first whitespace character + * after start. + */ + + if (NULL == end) + end = start + strcspn(start, ":"); + + int match_len = end - start; + + /* legacy special case for file urls. */ + if (strncasecmp(start, "file", 4) == 0) + return findScheme("ftp"); + for (scheme_vector::iterator i = schemes.begin(); + i != schemes.end(); ++i) { + char const * proto_string = (*i)->const_str(); + int proto_len = strlen(proto_string); + if (match_len == proto_len && strncasecmp(start, proto_string, proto_len) == 0) + return *i; + /* find the fallback protocol */ + if (strcmp((*i)->const_str(), "NONE") == 0) + fallback = *i; + } + return fallback; +} + +URLScheme::~URLScheme() +{ +} + +void +URLScheme::startFetch(HttpRequest *, StoreEntry *, int) const +{ + fatal_dump("unreachable base method"); +} + +bool +URLScheme::cacheable(HttpRequest const * request) const +{ + /* by default assume that any request does not prohibit caching */ + return true; +} + +String +URLScheme::canonicalUrl(HttpRequest const * request) const +{ + LOCAL_ARRAY(char, portbuf, 32); + LOCAL_ARRAY(char, urlbuf, MAX_URL); + + /* CONNECT URLs are special - no url scheme is given + * + * We should probably give CONNECT its own protocol scheme too. + */ + switch (request->method) { + + case METHOD_CONNECT: + snprintf(urlbuf, MAX_URL, "%s:%d", request->host, request->port); + break; + /* other URLS we format as a regular string */ + default: + portbuf[0] = '\0'; + + if (request->port != request->scheme->defaultPort()) + snprintf(portbuf, 32, ":%d", request->port); + + snprintf(urlbuf, MAX_URL, "%s://%s%s%s%s%s", + request->scheme->const_str(), + request->login, + *request->login ? "@" : null_string, + request->host, + portbuf, + request->urlpath.buf()); + + break; + } + return urlbuf; +} + +String +URLScheme::canonicalUrlClean(HttpRequest const * request) const +{ + String result = canonicalUrlCleanUncleaned(request); + if (stringHasCntl(result.buf())) + return rfc1738_escape_unescaped(result.buf()); + else + return result; +} + +String +URLScheme::canonicalUrlCleanUncleaned(HttpRequest const * request) const +{ + LOCAL_ARRAY(char, buf, MAX_URL); + LOCAL_ARRAY(char, portbuf, 32); + LOCAL_ARRAY(char, loginbuf, MAX_LOGIN_SZ + 1); + char *t; + + switch (request->method) { + + /* connect is special */ + case METHOD_CONNECT: + snprintf(buf, MAX_URL, "%s:%d", request->host, request->port); + break; + + /* everything else we format as a regular url */ + default: + portbuf[0] = '\0'; + + if (request->port != request->scheme->defaultPort()) + snprintf(portbuf, 32, ":%d", request->port); + + loginbuf[0] = '\0'; + + if ((int) strlen(request->login) > 0) { + strcpy(loginbuf, request->login); + + if ((t = strchr(loginbuf, ':'))) + *t = '\0'; + + strcat(loginbuf, "@"); + } + + snprintf(buf, MAX_URL, "%s://%s%s%s%s", + request->scheme->const_str(), + loginbuf, + request->host, + portbuf, + request->urlpath.buf()); + /* + * strip arguments AFTER a question-mark + */ + + if (Config.onoff.strip_query_terms) + if ((t = strchr(buf, '?'))) + *(++t) = '\0'; + + break; + } + return buf; +} + +bool +URLScheme::canServe(HttpRequest const * request) const +{ + bool rc = false; + /* does method match the protocol? + * - that is, are we being asked to do someting in 'generic' terms + * that we can actually do. We cant for instance accept put requests to + * our internal: url space... so this table is rather faulty + */ + /* it should look like + * return r->scheme->canHandle(r->method); + */ + switch ((protocol_t)(*this)) { + + case PROTO_HTTP: + + case PROTO_CACHEOBJ: + rc = true; + break; + + case PROTO_FTP: + + if (request->method == METHOD_PUT) + rc = true; + + case PROTO_WAIS: + + case PROTO_WHOIS: + if (request->method == METHOD_GET) + rc = true; + else if (request->method == METHOD_HEAD) + rc = true; + + break; + + case PROTO_HTTPS: +#ifdef USE_SSL + + rc = true; + + break; + +#else + /* + * Squid can't originate an SSL connection, so it should + * never receive an "https:" URL. It should always be + * CONNECT instead. + */ + rc = false; + +#endif + + default: + break; + } + + return rc; +} + +int +URLScheme::defaultPort() const +{ + switch((protocol_t)(*this)) { + + case PROTO_HTTP: + return 80; + + case PROTO_HTTPS: + return 443; + + case PROTO_FTP: + return 21; + + case PROTO_VIRTUAL: + case PROTO_BAD: + fatal_dump("Unreachable code!"); + + case PROTO_WAIS: + return 210; + + case PROTO_CACHEOBJ: + + case PROTO_INTERNAL: + return CACHE_HTTP_PORT; + + case PROTO_WHOIS: + return 43; + + default: + return 0; + } +} === modified file 'src/URLScheme.h' --- src/URLScheme.h 2006-05-21 00:15:01 +0000 +++ src/URLScheme.h 2006-08-27 23:20:16 +0000 @@ -41,8 +41,30 @@ extern const char *ProtocolStr[]; +class URLScheme; + +class URLSchemeRegistry { +public: + /* add a scheme to the registry */ + void registerScheme(URLScheme const *scheme); + /* find a scheme by an exact string match. */ + URLScheme const * findScheme(char const *start, char const *end = NULL); + /* generally there is only one registry, though tests may use more. */ + static URLSchemeRegistry &GetInstance(); + /* this is the NULLObject pattern - we have an explicit scheme to represent + * 'no scheme'. This is returned on misses in findScheme. + * Until we get rid of the overloading of connect with + * no-scheme requests (that are bogus), this is detected + * via checking the registry for NONE on the search/ + */ + // static URLScheme const *none; +private: + typedef Vector scheme_vector; + scheme_vector schemes; +}; + /* This class represents a URL Scheme such as HTTPS, HTTP, WAIS etc. - * It does not represent the PROTOCOL that such schemes refer to. + * It does not represent the wire PROTOCOL that such schemes refer to. */ class URLScheme @@ -50,16 +72,77 @@ public: URLScheme() : theScheme(PROTO_NONE) {} - URLScheme(protocol_t const aScheme) : theScheme(aScheme) {} - - operator protocol_t() const { return theScheme; } - - bool operator != (protocol_t const & aProtocol) const { return theScheme != aProtocol;} + URLScheme(URLSchemeRegistry ®istry) : theScheme(PROTO_NONE) { registry.registerScheme(this);} + + URLScheme(URLSchemeRegistry * registry, protocol_t const aScheme) : theScheme(aScheme) {if (registry) registry->registerScheme(this);} + + virtual ~URLScheme(); + + virtual operator protocol_t() const { return theScheme; } + + virtual bool operator != (protocol_t const & aProtocol) const { return theScheme != aProtocol;} /* Get a char string representation of the scheme. */ - char const *const_str() const { return ProtocolStr[theScheme]; } - + virtual char const *const_str() const { return ProtocolStr[theScheme]; } + + /* start a fetch of the data for a request into a store + * entry. + */ + virtual void startFetch(HttpRequest * request, StoreEntry * entry, int const client_fd) const /* =0 when we no longer create any URLScheme base objects */; + + /* Obtain a canonical representation of a url in this scheme */ + virtual String canonicalUrl(HttpRequest const * request) const; + + /* Obtain a clean representation of a url. The clean representation is + * suitable for logging etc - it has no control characters, has query + * items stripped if that has been configured etc. + */ + String canonicalUrlClean(HttpRequest const * request) const; + /* helper function for canonicalUrlClean: + * this is called by canonicalUrlClean to generate a url which is + * sanitised for content, but may still ahve ntrl characters in it. + */ + virtual String canonicalUrlCleanUncleaned(HttpRequest const * request) const; + /* Can a specific request be served by squid? If false then an error is + * given to the client. + */ + virtual bool canServe(HttpRequest const * request) const; + + /* Is it potentially possible to cache the response to a specific + * Request ? If it is not, we may want to skip using the cache hierarchy. + * This possibly should be a method on the request, if the request varied + * per url type. + */ + virtual bool cacheable(HttpRequest const * request) const; + + /* What is the default port for this scheme ? This is strictly only needed + * for urls that can have ports. + */ + virtual int defaultPort() const; + /* XXX functions to add: + * // return true if this protocol can be revalidated or false if a cache + * // miss requires a new retrieval every time + * supportsRevalidate(); + * // return true if this protocol will fetch remote data + * fetchesRemoteData(); + * // a peer has been connected too - start a request on it + * // only needed for fetchesRemoteData instances. + * peerConnected(); + * // format a url for the error page when it had a 2f hack. + * // probably should be on request + * formatRequestURLFTPWith2f() + * // this request was an HTTPS request. Better than a typecode because + * // a new scheme like TLS may want to claim to be HTTPS in this manner + * isHTTPS(); + * // supply a 'direct' peer on request.. WAIS uses a configured peer rather + * // than using NULL - which forward.cc takes to mean 'do a DNS choice' + * // because WAIS is not natively spoken by squid and needs a peer to + * // talk to. + * getDirectPeer(); + * + * + */ private: /* This is a typecode for now - TODO make the varying methods virtual * Doing that without doubling the storage size will require having === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2006-08-05 00:43:20 +0000 +++ src/cache_cf.cc 2006-08-26 06:45:02 +0000 @@ -45,6 +45,7 @@ #include "StoreFileSystem.h" #include "Parsing.h" #include "MemBuf.h" +#include "neighbors.h" #include "wordlist.h" #if SQUID_SNMP === modified file 'src/cache_manager.cc' --- src/cache_manager.cc 2006-08-20 08:59:21 +0000 +++ src/cache_manager.cc 2006-08-24 11:29:30 +0000 @@ -42,6 +42,8 @@ #include "SquidTime.h" #include "wordlist.h" +static URLSchemeCacheObject cache_object(URLSchemeRegistry::GetInstance()); + #define MGR_PASSWD_SZ 128 typedef struct @@ -238,8 +240,16 @@ xfree(mgr); } +URLSchemeCacheObject::URLSchemeCacheObject() : URLScheme(NULL, PROTO_CACHEOBJ) +{ +} + +URLSchemeCacheObject::URLSchemeCacheObject(URLSchemeRegistry ®istry) : URLScheme(®istry, PROTO_CACHEOBJ) +{ +} + void -cachemgrStart(int fd, HttpRequest * request, StoreEntry * entry) +URLSchemeCacheObject::startFetch(HttpRequest * request, StoreEntry * entry, int fd) const { cachemgrStateData *mgr = NULL; ErrorState *err = NULL; === modified file 'src/carp.cc' --- src/carp.cc 2006-05-29 00:05:21 +0000 +++ src/carp.cc 2006-08-26 06:45:42 +0000 @@ -36,6 +36,7 @@ #include "squid.h" #include "CacheManager.h" +#include "neighbors.h" #include "Store.h" #if USE_CARP === modified file 'src/client_side.cc' --- src/client_side.cc 2006-08-05 00:43:20 +0000 +++ src/client_side.cc 2006-08-24 01:51:10 +0000 @@ -74,6 +74,7 @@ #include "ClientRequestContext.h" #include "MemBuf.h" #include "SquidTime.h" +#include "URLScheme.h" #if LINGERING_CLOSE #define comm_close comm_lingering_close @@ -2291,7 +2292,10 @@ } if (http->flags.internal) { - request->protocol = PROTO_HTTP; + /* RC: why do we force the scheme to be HTTP ? we have an internal + * url space already... + */ + request->scheme = URLSchemeRegistry::GetInstance().findScheme("http"); request->login[0] = '\0'; } === modified file 'src/client_side_reply.cc' --- src/client_side_reply.cc 2006-08-20 08:59:21 +0000 +++ src/client_side_reply.cc 2006-08-24 07:16:48 +0000 @@ -58,6 +58,7 @@ #endif #include "client_side.h" #include "SquidTime.h" +#include "URLScheme.h" CBDATA_CLASS_INIT(clientReplyContext); @@ -585,10 +586,12 @@ */ http->logType = LOG_TCP_CLIENT_REFRESH_MISS; processMiss(); - } else if (r->protocol == PROTO_HTTP) { + } else if ((protocol_t)(*r->scheme) == PROTO_HTTP) { + /* XXX should be if r->scheme->supportsRevalidate() */ /* * Object needs to be revalidated * XXX This could apply to FTP as well, if Last-Modified is known. + * XXX and what about HTTPS ? */ processExpired(); } else { @@ -718,7 +721,11 @@ } if (http->flags.internal) - r->protocol = PROTO_INTERNAL; + /* XXX: + * why do we poke at this here? why not have it as internal from + * when it was parsed ? + */ + r->scheme = URLSchemeRegistry::GetInstance().findScheme("internal"); FwdState::fwdStart(http->getConn().getRaw() != NULL ? http->getConn()->fd : -1, http->storeEntry(), @@ -2042,7 +2049,7 @@ */ if (http->request == NULL) - http->request = HTTPMSGLOCK(new HttpRequest(m, PROTO_NONE, null_string)); + http->request = HTTPMSGLOCK(new HttpRequest(m, URLSchemeRegistry::GetInstance().findScheme("NONE"), null_string)); StoreEntry *e = storeCreateEntry(http->uri, http->log_uri, flags, m); === modified file 'src/client_side_request.cc' --- src/client_side_request.cc 2006-08-05 00:43:20 +0000 +++ src/client_side_request.cc 2006-08-27 23:46:06 +0000 @@ -55,6 +55,7 @@ #include "MemObject.h" #include "ClientRequestContext.h" #include "SquidTime.h" +#include "URLScheme.h" #include "wordlist.h" #if ICAP_CLIENT @@ -584,6 +585,10 @@ if (request->flags.auth) return 0; + /* if we've been asked to trace, surely we should still honour + * the logic for the request - stop lists etc ? + * also, this should be after loop detection. + */ if (method == METHOD_TRACE) return 1; @@ -598,16 +603,16 @@ if (request->flags.loopdetect) return 0; - if (request->protocol == PROTO_HTTP) + /* AIMING FOR just return request->scheme->cacheable(request); */ + if ((protocol_t)(*request->scheme) == PROTO_VIRTUAL) + return request->scheme->cacheable(request); + if ((protocol_t)(*request->scheme) == PROTO_HTTP) return httpCachable(method); - if (request->protocol == PROTO_GOPHER) - return gopherCachable(request); - - if (request->protocol == PROTO_WAIS) + if ((protocol_t)(*request->scheme) == PROTO_WAIS) return 0; - if (request->protocol == PROTO_CACHEOBJ) + if ((protocol_t)(*request->scheme) == PROTO_CACHEOBJ) return 0; return 1; === modified file 'src/enums.h' --- src/enums.h 2006-08-21 00:32:38 +0000 +++ src/enums.h 2006-08-27 23:47:00 +0000 @@ -239,17 +239,17 @@ PROTO_NONE, PROTO_HTTP, PROTO_FTP, - PROTO_GOPHER, PROTO_WAIS, PROTO_CACHEOBJ, PROTO_ICP, #if USE_HTCP PROTO_HTCP, #endif - PROTO_URN, PROTO_WHOIS, PROTO_INTERNAL, PROTO_HTTPS, + PROTO_BAD, /* A bad / invalid protocol request. */ + PROTO_VIRTUAL, /* using the virtual scheme facilities */ PROTO_MAX } protocol_t; === modified file 'src/errorpage.cc' --- src/errorpage.cc 2006-08-20 08:59:21 +0000 +++ src/errorpage.cc 2006-08-24 02:03:58 +0000 @@ -738,7 +738,7 @@ break; case 'P': - p = r ? ProtocolStr[r->protocol] : "[unknown protocol]"; + p = (r && r->scheme) ? r->scheme->const_str() : "[unknown protocol]"; break; case 'R': === modified file 'src/external_acl.cc' --- src/external_acl.cc 2006-08-20 02:36:53 +0000 +++ src/external_acl.cc 2006-08-24 02:05:53 +0000 @@ -801,7 +801,7 @@ break; case _external_acl_format::EXT_ACL_PROTO: - str = ProtocolStr[request->protocol]; + str = request->scheme->const_str(); break; case _external_acl_format::EXT_ACL_PORT: === modified file 'src/forward.cc' --- src/forward.cc 2006-08-20 08:59:21 +0000 +++ src/forward.cc 2006-08-27 23:46:22 +0000 @@ -48,8 +48,8 @@ #include "pconn.h" #include "SquidTime.h" #include "Store.h" +#include "URLScheme.h" -static PSC fwdStartCompleteWrapper; static PF fwdServerClosedWrapper; #if USE_SSL static PF fwdNegotiateSSLWrapper; @@ -72,6 +72,23 @@ static PconnPool *fwdPconnPool = new PconnPool("server-side"); CBDATA_CLASS_INIT(FwdState); +/* Register the protocols that go via this module + * none really should not be here, but its a legacy issue: + * CONNECT requests have protocol None, which leads to the + * rather confusing situation where the /default/ scheme + * can be forwarded. + */ +static URLSchemeForwardable none(&URLSchemeRegistry::GetInstance(), PROTO_NONE); +static URLSchemeForwardable http(&URLSchemeRegistry::GetInstance(), PROTO_HTTP); +static URLSchemeForwardable ftp(&URLSchemeRegistry::GetInstance(), PROTO_FTP); +static URLSchemeForwardable wais(&URLSchemeRegistry::GetInstance(), PROTO_WAIS); +static URLSchemeForwardable icp(&URLSchemeRegistry::GetInstance(), PROTO_ICP); +#if USE_HTCP +static URLSchemeForwardable htcp(&URLSchemeRegistry::GetInstance(), PROTO_HTCP); +#endif +static URLSchemeForwardable whois(&URLSchemeRegistry::GetInstance(), PROTO_WHOIS); +static URLSchemeForwardable https(&URLSchemeRegistry::GetInstance(), PROTO_HTTPS); + void FwdState::abort(void* d) { @@ -94,14 +111,9 @@ server_fd = -1; request = HTTPMSGLOCK(r); start_t = squid_curtime; - - e->lock() - - ; + e->lock(); EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT); - - self = this; // refcounted - + self = this; // refcounted storeRegisterAbort(e, FwdState::abort, this); } @@ -171,7 +183,11 @@ * be allowed. yuck, I know. */ - if (request->client_addr.s_addr != no_addr.s_addr && request->protocol != PROTO_INTERNAL && request->protocol != PROTO_CACHEOBJ) { + if (request->client_addr.s_addr != no_addr.s_addr && + /* internal and cacheobj dont ever fetch */ + /* XXX should be request->scheme->fetchesRemoteData() */ + (protocol_t)(*request->scheme) != PROTO_INTERNAL && + (protocol_t)(*request->scheme) != PROTO_CACHEOBJ) { /* * Check if this host is allowed to fetch MISSES from us (miss_access) */ @@ -197,20 +213,19 @@ anErr->src_addr = request->client_addr; - errorAppendEntry(entry, anErr); // frees anErr + errorAppendEntry(entry, anErr); // frees anErr return; } } - debug(17, 3) ("FwdState::start() '%s'\n", storeUrl(entry)); + debugs(17, 3, "FwdState::start() '" << storeUrl(entry) << "'"); /* * This seems like an odd place to bind mem_obj and request. * Might want to assert that request is NULL at this point */ entry->mem_obj->request = HTTPMSGLOCK(request); #if URL_CHECKSUM_DEBUG - entry->mem_obj->checkUrlChecksum(); #endif @@ -218,30 +233,48 @@ /* more yuck */ ErrorState *anErr = errorCon(ERR_SHUTTING_DOWN, HTTP_SERVICE_UNAVAILABLE); anErr->request = HTTPMSGLOCK(request); - errorAppendEntry(entry, anErr); // frees anErr + errorAppendEntry(entry, anErr); // frees anErr return; } - switch (request->protocol) { - + request->startFetch(entry, client_fd); +} + +/* Peer servers selected, try forwarding */ +static void +peerSelectComplete(FwdServer *servers, void *data) +{ + FwdState * fwd = static_cast(data); + if (servers != NULL) + /* forward the request */ + fwd->forwardToServers(servers); + else + fwd->startFail(); +} + +/* generic base behaviour for URLSchemes that can be + * forwarded via our peers. + */ +void +URLSchemeForwardable::startFetch(HttpRequest * request, StoreEntry * entry, int const client_fd) const +{ + switch ((protocol_t)(*this)) { + + /* These protocols have been refactored into subclasses + * of URLScheme and should not reach this method. + */ + case PROTO_CACHEOBJ: case PROTO_INTERNAL: - internalStart(request, entry); - return; - - case PROTO_CACHEOBJ: - cachemgrStart(client_fd, request, entry); - return; - - case PROTO_URN: - urnStart(request, entry); + case PROTO_BAD: + fatal_dump("unreachable"); return; default: + /* select what peers to forward this request to */ FwdState *fwd = new FwdState(client_fd, entry, request); - peerSelect(request, entry, fwdStartCompleteWrapper, fwd); + peerSelect(request, entry, peerSelectComplete, fwd); return; } - /* NOTREACHED */ } @@ -278,15 +311,15 @@ /* * server-side modules call fwdComplete() when they are done * downloading an object. Then, we either 1) re-forward the - * request somewhere else if needed, or 2) call storeComplete() - * to finish it off + * request somewhere else if needed (i.e. we got a 500 http error), + * or 2) call storeComplete() to finish it off */ void FwdState::complete() { StoreEntry *e = entry; assert(entry->store_status == STORE_PENDING); - debug(17, 3) ("fwdComplete: %s\n\tstatus %d\n", storeUrl(e), + debug(17, 3) ("fwdComplete: %s\n\tstatus %d\n", storeUrl(entry), entry->getReply()->sline.status); #if URL_CHECKSUM_DEBUG @@ -298,7 +331,7 @@ if (reforward()) { debug(17, 3) ("fwdComplete: re-forwarding %d %s\n", entry->getReply()->sline.status, - storeUrl(e)); + storeUrl(entry)); if (server_fd > -1) unregister(server_fd); @@ -311,9 +344,11 @@ * ref count could go to zero before a connection is * established. */ - self = this; // refcounted + self = this; // refcounted - startComplete(servers); + /* we always have a server available - reforward checks that */ + assert(servers != NULL); + connectStart(); } else { debug(17, 3) ("fwdComplete: not re-forwarding status %d\n", entry->getReply()->sline.status); @@ -325,12 +360,6 @@ /**** CALLBACK WRAPPERS ************************************************************/ -static void -fwdStartCompleteWrapper(FwdServer * servers, void *data) -{ - FwdState *fwd = (FwdState *) data; - fwd->startComplete(servers); -} static void fwdServerClosedWrapper(int fd, void *data) @@ -492,7 +521,7 @@ anErr->request = HTTPMSGLOCK(request); } - self = NULL; // refcounted + self = NULL; // refcounted } #if USE_SSL @@ -575,7 +604,7 @@ anErr->xerrno = errno; anErr->request = HTTPMSGLOCK(request); fail(anErr); - self = NULL; // refcounted + self = NULL; // refcounted return; } @@ -782,7 +811,7 @@ ErrorState *anErr = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR); anErr->xerrno = errno; fail(anErr); - self = NULL; // refcounted + self = NULL; // refcounted return; } @@ -816,29 +845,30 @@ commConnectStart(fd, host, port, fwdConnectDoneWrapper, this); } +/* + * Forward this request to the servers provided. If none have been supplied, + * then fail + */ void -FwdState::startComplete(FwdServer * theServers) +FwdState::forwardToServers(FwdServer * theServers) { - debug(17, 3) ("fwdStartComplete: %s\n", storeUrl(entry)); - - if (theServers != NULL) { - servers = theServers; - connectStart(); - } else { - startFail(); - } + debugs(17, 3, "FwdState::peersSelected: " << storeUrl(entry)); + assert(theServers != NULL); + servers = theServers; + connectStart(); } void FwdState::startFail() { - debug(17, 3) ("fwdStartFail: %s\n", storeUrl(entry)); + debugs(17, 3, "fwdStartFail: " << storeUrl(entry)); ErrorState *anErr = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE); anErr->xerrno = errno; fail(anErr); - self = NULL; // refcounted + self = NULL; // refcounted } +/* after connecting, give the request to a server side module */ void FwdState::dispatch() { @@ -867,6 +897,13 @@ netdbPingSite(request->host); + /* here is where the wire scheme and the request scheme should be + * disambiguated: + * rather than calling httpStart, we could call + * p->connectedToServer, which would set the peer login and then call + * this->scheme->connectedToServer or similar, which would open the + * gate to having non-HTTP peers + */ if (servers && (p = servers->_peer)) { p->stats.fetches++; request->peer_login = p->login; @@ -875,62 +912,13 @@ } else { request->peer_login = NULL; request->peer_domain = NULL; - - switch (request->protocol) { -#if USE_SSL - - case PROTO_HTTPS: - httpStart(this); - break; -#endif - - case PROTO_HTTP: - httpStart(this); - break; - - case PROTO_GOPHER: - gopherStart(this); - break; - - case PROTO_FTP: - ftpStart(this); - break; - - case PROTO_WAIS: - waisStart(this); - break; - - case PROTO_CACHEOBJ: - - case PROTO_INTERNAL: - - case PROTO_URN: + URLSchemeForwardable const *forwardable_scheme = dynamic_cast(request->scheme); + if (forwardable_scheme == NULL) + /* We got a non-forwardable - i.e. internal object, cacheobject, + * urn or other has-own-network-implementation scheme + */ fatal_dump("Should never get here"); - break; - - case PROTO_WHOIS: - whoisStart(this); - break; - - default: - debug(17, 1) ("fwdDispatch: Cannot retrieve '%s'\n", - storeUrl(entry)); - ErrorState *anErr = errorCon(ERR_UNSUP_REQ, HTTP_BAD_REQUEST); - fail(anErr); - /* - * Force a persistent connection to be closed because - * some Netscape browsers have a bug that sends CONNECT - * requests as GET's over persistent connections. - */ - request->flags.proxy_keepalive = 0; - /* - * Set the dont_retry flag becuase this is not a - * transient (network) error; its a bug. - */ - flags.dont_retry = 1; - comm_close(server_fd); - break; - } + forwardable_scheme->connectedToServer(this); } /* @@ -940,6 +928,78 @@ self = NULL; } +void +URLSchemeForwardable::connectedToServer(FwdState * fwdState) const +{ + /* NB: these protocols imply over-the-network can-be-handed-to-peers + * via http + */ + switch ((protocol_t)(*fwdState->request->scheme)) { +#if USE_SSL + + case PROTO_HTTPS: + httpStart(fwdState); + break; +#endif + + case PROTO_HTTP: + httpStart(fwdState); + break; + + case PROTO_FTP: + ftpStart(fwdState); + break; + + case PROTO_WAIS: + waisStart(fwdState); + break; + + /* these three protocols do not connect to peers - they + * should not be in the forward logic at all + * : This is now trapped by the dynamic cast in ::dispatch, but until + * we finish the breakout, keeping the if block is useful. + */ + case PROTO_CACHEOBJ: + case PROTO_INTERNAL: + case PROTO_BAD: + fatal_dump("Should never get here"); + break; + + /* upgraded to virtual logic */ + case PROTO_VIRTUAL: + fatal_dump("should never get here"); + + case PROTO_WHOIS: + whoisStart(fwdState); + break; + + default: + debug(17, 1) ("fwdDispatch: Cannot retrieve '%s'\n", + storeUrl(fwdState->entry)); + ErrorState *anErr = errorCon(ERR_UNSUP_REQ, HTTP_BAD_REQUEST); + fwdState->fail(anErr); + /* + * Force a persistent connection to be closed because + * some Netscape browsers have a bug that sends CONNECT + * requests as GET's over persistent connections. + */ + fwdState->request->flags.proxy_keepalive = 0; + /* + * Set the dont_retry flag becuase this is not a + * transient (network) error; its a bug. + */ + fwdState->preventRetry(); + comm_close(fwdState->server_fd); + break; + } +} + +void +FwdState::preventRetry() +{ + flags.dont_retry = 1; +} + int FwdState::reforward() { === modified file 'src/forward.h' --- src/forward.h 2006-08-20 08:59:21 +0000 +++ src/forward.h 2006-08-27 23:06:35 +0000 @@ -7,6 +7,7 @@ class ErrorState; #include "comm.h" +#include "URLScheme.h" class FwdServer { @@ -28,9 +29,10 @@ static void RegisterWithCacheManager(CacheManager & manager); static void fwdStart(int fd, StoreEntry *, HttpRequest *); - void startComplete(FwdServer *); + void forwardToServers(FwdServer *); void startFail(); void fail(ErrorState *err); + void preventRetry(); void unregister(int fd); void complete(); int reforward(); @@ -88,16 +90,29 @@ struct { - -unsigned int dont_retry: - 1; - -unsigned int ftp_pasv_failed: - 1; + unsigned int dont_retry: 1; + unsigned int ftp_pasv_failed: 1; } flags; }; +class URLSchemeForwardable : public URLScheme +{ +public: + URLSchemeForwardable(URLSchemeRegistry *registry, protocol_t proto) : URLScheme(registry, proto) {}; + URLSchemeForwardable(protocol_t proto) : URLScheme(proto) {} + virtual void startFetch(HttpRequest * request, StoreEntry * entry, int client_fd) const; + + /* For forwardable urls, We've connected to the server and now need to + * actually submit a request etc etc. + * + * This is not a method on the base URLScheme, only on ones that use the + * squid forwarding infrastructure... other schemes may choose to implement + * it themselves, but will also need to arrange for it to be called. + */ + virtual void connectedToServer(FwdState * fwdState) const; +}; + #endif === modified file 'src/ftp.cc' --- src/ftp.cc 2006-08-20 08:59:21 +0000 +++ src/ftp.cc 2006-08-27 23:37:12 +0000 @@ -1407,6 +1407,9 @@ } } +/* This looks like a variation on canonicalUrlClean, perhaps that would be + * a better thing to call? + */ void FtpStateData::buildTitleUrl() { @@ -1419,7 +1422,7 @@ title_url.append(request->host); - if (request->port != urlDefaultPort(PROTO_FTP)) { + if (request->port != request->scheme->defaultPort()) { title_url.append(":"); title_url.append(xitoa(request->port)); } @@ -1441,7 +1444,7 @@ base_href.append(request->host); - if (request->port != urlDefaultPort(PROTO_FTP)) { + if (request->port != request->scheme->defaultPort()) { base_href.append(":"); base_href.append(xitoa(request->port)); } @@ -3198,10 +3201,14 @@ char *t; portbuf[0] = '\0'; - if (request->protocol != PROTO_FTP) + /* this is always called when %B is used, but it may not be + * a ftp request. This should be a virtual method on the + * protocol + */ + if ((protocol_t)(*request->scheme) != PROTO_FTP) return NULL; - if (request->port != urlDefaultPort(request->protocol)) + if (request->port != request->scheme->defaultPort()) snprintf(portbuf, 32, ":%d", request->port); loginbuf[0] = '\0'; @@ -3216,7 +3223,7 @@ } snprintf(buf, MAX_URL, "%s://%s%s%s%s%s", - ProtocolStr[request->protocol], + request->scheme->const_str(), loginbuf, request->host, portbuf, === modified file 'src/gopher.cc' --- src/gopher.cc 2006-08-20 08:59:21 +0000 +++ src/gopher.cc 2006-08-27 23:55:00 +0000 @@ -34,6 +34,7 @@ */ #include "squid.h" +#include "gopher.h" #include "errorpage.h" #include "Store.h" #include "HttpRequest.h" @@ -46,6 +47,8 @@ #include "forward.h" #include "SquidTime.h" +static URLSchemeGopher gopher(URLSchemeRegistry::GetInstance()); + /* gopher type code from rfc. Anawat. */ #define GOPHER_FILE '0' #define GOPHER_DIRECTORY '1' @@ -252,13 +255,16 @@ } } -int -gopherCachable(const HttpRequest * req) +/* + * All gopher requests get cached except for INDEX, CSO, TELNET and 3270. + */ +bool +URLSchemeGopher::cacheable(HttpRequest const * request) const { int cachable = 1; char type_id; /* parse to see type */ - gopher_request_parse(req, + gopher_request_parse(request, &type_id, NULL); @@ -935,7 +941,7 @@ CBDATA_TYPE(GopherStateData); void -gopherStart(FwdState * fwd) +URLSchemeGopher::connectedToServer(FwdState * fwd) const { int fd = fwd->server_fd; StoreEntry *entry = fwd->entry; @@ -944,17 +950,11 @@ gopherState = cbdataAlloc(GopherStateData); gopherState->buf = (char *)memAllocate(MEM_4K_BUF); - entry->lock() - - ; + entry->lock(); gopherState->entry = entry; - gopherState->fwd = fwd; - debug(10, 3) ("gopherStart: %s\n", storeUrl(entry)); - statCounter.server.all.requests++; - statCounter.server.other.requests++; /* Parse url. */ @@ -963,6 +963,9 @@ comm_add_close_handler(fd, gopherStateFree, gopherState); + /* FIXME: we should override startFetch so that we can perform this check + * before contacting the remote server - RC 20060827 + */ if (((gopherState->type_id == GOPHER_INDEX) || (gopherState->type_id == GOPHER_CSO)) && (strchr(gopherState->request, '?') == NULL)) { /* Index URL without query word */ @@ -990,3 +993,16 @@ gopherSendRequest(fd, gopherState); commSetTimeout(fd, Config.Timeout.read, gopherTimeout, gopherState); } + +/* We only map GET and HEAD to the gopher protocol. */ +bool +URLSchemeGopher::canServe(HttpRequest const * request) const +{ + return request->method == METHOD_GET || request->method == METHOD_HEAD; +} + +int +URLSchemeGopher::defaultPort() const +{ + return 70; +} === modified file 'src/http.cc' --- src/http.cc 2006-08-20 08:59:21 +0000 +++ src/http.cc 2006-08-27 23:38:15 +0000 @@ -61,6 +61,7 @@ extern ICAPConfig TheICAPConfig; #endif #include "SquidTime.h" +#include "URLScheme.h" CBDATA_CLASS_INIT(HttpStateData); @@ -97,7 +98,7 @@ url = storeUrl(entry); HttpRequest * proxy_req = new HttpRequest(orig_request->method, - orig_request->protocol, url); + orig_request->scheme, url); xstrncpy(proxy_req->host, _peer->host, SQUIDHOSTNAMELEN); @@ -1403,10 +1404,10 @@ if (!hdr_out->has(HDR_HOST)) { if (orig_request->peer_domain) { hdr_out->putStr(HDR_HOST, orig_request->peer_domain); - } else if (orig_request->port == urlDefaultPort(orig_request->protocol)) { - /* use port# only if not default */ + } else if (orig_request->port == orig_request->scheme->defaultPort()) { hdr_out->putStr(HDR_HOST, orig_request->host); } else { + /* use port# only if not default */ httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d", orig_request->host, (int) orig_request->port); } @@ -1531,7 +1532,7 @@ /* append Front-End-Https */ if (flags.front_end_https) { - if (flags.front_end_https == 1 || request->protocol == PROTO_HTTPS) + if (flags.front_end_https == 1 || (protocol_t)(*request->scheme) == PROTO_HTTPS) hdr_out->putStr(HDR_FRONT_END_HTTPS, "On"); } @@ -1600,7 +1601,7 @@ else { /* use port# only if not default */ - if (orig_request->port == urlDefaultPort(orig_request->protocol)) { + if (orig_request->port == orig_request->scheme->defaultPort()) { hdr_out->putStr(HDR_HOST, orig_request->host); } else { httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d", === modified file 'src/icp_v2.cc' --- src/icp_v2.cc 2006-08-19 12:32:09 +0000 +++ src/icp_v2.cc 2006-08-26 07:04:41 +0000 @@ -41,6 +41,7 @@ #include "ACLChecklist.h" #include "ACL.h" #include "AccessLogEntry.h" +#include "neighbors.h" #include "wordlist.h" #include "SquidTime.h" #include "SwapDir.h" === modified file 'src/internal.cc' --- src/internal.cc 2006-08-20 08:59:21 +0000 +++ src/internal.cc 2006-08-27 23:39:07 +0000 @@ -34,6 +34,7 @@ */ #include "squid.h" +#include "internal.h" #include "errorpage.h" #include "Store.h" #include "HttpRequest.h" @@ -42,12 +43,24 @@ #include "SquidTime.h" #include "wordlist.h" +static URLSchemeInternal internal(URLSchemeRegistry::GetInstance()); + +/* Create an internal url scheme instance */ +URLSchemeInternal::URLSchemeInternal() +{ +} + +/* Create and register in a registry a url scheme instance */ +URLSchemeInternal::URLSchemeInternal(URLSchemeRegistry ®istry) : URLScheme(registry) +{ +} + /* called when we "miss" on an internal object; * generate known dynamic objects, * return HTTP_NOT_FOUND for others */ void -internalStart(HttpRequest * request, StoreEntry * entry) +URLSchemeInternal::startFetch(HttpRequest * request, StoreEntry * entry, int client_fd) const { ErrorState *err; const char *upath = request->urlpath.buf(); @@ -125,7 +138,7 @@ mb.Printf("http://%s", lc_host); /* append port if not default */ - if (port && port != urlDefaultPort(PROTO_HTTP)) + if (port && port != internal.defaultPort()) mb.Printf(":%d", port); if (dir) === modified file 'src/main.cc' --- src/main.cc 2006-08-21 00:52:34 +0000 +++ src/main.cc 2006-08-26 07:09:30 +0000 @@ -47,6 +47,7 @@ #include "HttpReply.h" #include "pconn.h" #include "Mem.h" +#include "neighbors.h" #include "ACLASN.h" #include "ACL.h" #include "htcp.h" === modified file 'src/peer_select.cc' --- src/peer_select.cc 2006-08-20 02:36:53 +0000 +++ src/peer_select.cc 2006-08-26 07:05:29 +0000 @@ -39,9 +39,11 @@ #include "Store.h" #include "ICP.h" #include "HttpRequest.h" +#include "neighbors.h" #include "ACLChecklist.h" #include "htcp.h" #include "forward.h" +#include "URLScheme.h" const char *hier_strings[] = { @@ -498,8 +500,11 @@ if (ps->direct == DIRECT_NO) return; - if (ps->request->protocol == PROTO_WAIS) - /* Its not really DIRECT, now is it? */ + if ((protocol_t)(*ps->request->scheme) == PROTO_WAIS) + /* Its not really DIRECT, now is it? + * ... what stops use using the right HIER code here ? + * ... what will break ? RC 2006 + */ peerAddFwdServer(&ps->servers, Config.Wais._peer, HIER_DIRECT); else peerAddFwdServer(&ps->servers, NULL, HIER_DIRECT); === modified file 'src/protos.h' --- src/protos.h 2006-08-21 00:32:38 +0000 +++ src/protos.h 2006-08-27 23:55:06 +0000 @@ -181,10 +181,6 @@ SQUIDCEXTERN void ftpStart(FwdState *); SQUIDCEXTERN char *ftpUrlWith2f(const HttpRequest *); -SQUIDCEXTERN void gopherStart(FwdState *); -SQUIDCEXTERN int gopherCachable(const HttpRequest *); - - SQUIDCEXTERN void whoisStart(FwdState *); /* http.c */ @@ -352,45 +348,6 @@ /* put them all here for easier reference when writing a logfile analyzer */ -SQUIDCEXTERN peer *getFirstPeer(void); -SQUIDCEXTERN peer *getFirstUpParent(HttpRequest *); -SQUIDCEXTERN peer *getNextPeer(peer *); -SQUIDCEXTERN peer *getSingleParent(HttpRequest *); -SQUIDCEXTERN int neighborsCount(HttpRequest *); -SQUIDCEXTERN int neighborsUdpPing(HttpRequest *, - StoreEntry *, - IRCB * callback, - void *data, - int *exprep, - int *timeout); -SQUIDCEXTERN void neighborAddAcl(const char *, const char *); - -SQUIDCEXTERN void neighborsUdpAck(const cache_key *, icp_common_t *, const struct sockaddr_in *); -SQUIDCEXTERN void neighborAdd(const char *, const char *, int, int, int, int, int); -SQUIDCEXTERN void neighbors_init(void); -extern void neighborsRegisterWithCacheManager(CacheManager & manager); -SQUIDCEXTERN peer *peerFindByName(const char *); -SQUIDCEXTERN peer *peerFindByNameAndPort(const char *, unsigned short); -SQUIDCEXTERN peer *getDefaultParent(HttpRequest * request); -SQUIDCEXTERN peer *getRoundRobinParent(HttpRequest * request); -SQUIDCEXTERN peer *getWeightedRoundRobinParent(HttpRequest * request); -SQUIDCEXTERN void peerClearRR(void *); -SQUIDCEXTERN peer *getAnyParent(HttpRequest * request); -SQUIDCEXTERN lookup_t peerDigestLookup(peer * p, HttpRequest * request); -SQUIDCEXTERN peer *neighborsDigestSelect(HttpRequest * request); -SQUIDCEXTERN void peerNoteDigestLookup(HttpRequest * request, peer * p, lookup_t lookup); -SQUIDCEXTERN void peerNoteDigestGone(peer * p); -SQUIDCEXTERN int neighborUp(const peer * e); -SQUIDCEXTERN CBDUNL peerDestroy; -SQUIDCEXTERN const char *neighborTypeStr(const peer * e); -SQUIDCEXTERN peer_t neighborType(const peer *, const HttpRequest *); -SQUIDCEXTERN void peerConnectFailed(peer *); -SQUIDCEXTERN void peerConnectSucceded(peer *); -SQUIDCEXTERN void dump_peer_options(StoreEntry *, peer *); -SQUIDCEXTERN int peerHTTPOkay(const peer *, HttpRequest *); - -SQUIDCEXTERN peer *whichPeer(const struct sockaddr_in *from); - SQUIDCEXTERN void netdbInit(void); extern void netdbRegisterWitHCacheManager(CacheManager & manager); @@ -424,7 +381,6 @@ SQUIDCEXTERN struct IN_ADDR getOutgoingAddr(HttpRequest * request); unsigned long getOutgoingTOS(HttpRequest * request); -SQUIDCEXTERN void urnStart(HttpRequest *, StoreEntry *); SQUIDCEXTERN void redirectInit(void); extern void redirectRegisterWithCacheManager(CacheManager & manager); @@ -631,7 +587,6 @@ SQUIDCEXTERN char *url_convert_hex(char *org_url, int allocate); SQUIDCEXTERN char *url_escape(const char *url); -SQUIDCEXTERN protocol_t urlParseProtocol(const char *, const char *e = NULL); SQUIDCEXTERN void urlInitialize(void); SQUIDCEXTERN HttpRequest *urlParse(method_t, char *, HttpRequest *request = NULL); SQUIDCEXTERN const char *urlCanonical(HttpRequest *); @@ -702,7 +657,6 @@ SQUIDCEXTERN void cacheDigestGuessStatsReport(const cd_guess_stats * stats, StoreEntry * sentry, const char *label); SQUIDCEXTERN void cacheDigestReport(CacheDigest * cd, const char *label, StoreEntry * e); -SQUIDCEXTERN void internalStart(HttpRequest *, StoreEntry *); SQUIDCEXTERN int internalCheck(const char *urlpath); SQUIDCEXTERN int internalStaticCheck(const char *urlpath); SQUIDCEXTERN char *internalLocalUri(const char *dir, const char *name); === modified file 'src/snmp_agent.cc' --- src/snmp_agent.cc 2006-05-21 00:15:01 +0000 +++ src/snmp_agent.cc 2006-08-26 07:06:05 +0000 @@ -38,6 +38,7 @@ #include "cache_snmp.h" #include "Store.h" #include "mem_node.h" +#include "neighbors.h" /************************************************************************ === modified file 'src/tests/stub_HttpRequest.cc' --- src/tests/stub_HttpRequest.cc 2006-04-23 09:59:25 +0000 +++ src/tests/stub_HttpRequest.cc 2006-08-24 02:54:31 +0000 @@ -41,7 +41,7 @@ fatal("Not implemented"); } -HttpRequest::HttpRequest(method_t method, protocol_t protocol, const char *aUrlpath) : HttpMsg(hoRequest) +HttpRequest::HttpRequest(method_t method, URLScheme const *, const char *aUrlpath) : HttpMsg(hoRequest) { fatal("Not implemented"); } @@ -82,7 +82,7 @@ } void -HttpRequest::initHTTP(method_t aMethod, protocol_t aProtocol, const char *aUrlpath) +HttpRequest::initHTTP(method_t aMethod, URLScheme const *, const char *aUrlpath) { fatal("Not implemented"); } === modified file 'src/tests/testHttpRequest.cc' --- src/tests/testHttpRequest.cc 2006-05-05 10:50:50 +0000 +++ src/tests/testHttpRequest.cc 2006-08-24 07:34:02 +0000 @@ -4,6 +4,7 @@ #include "Mem.h" #include "testHttpRequest.h" #include "HttpRequest.h" +#include "URLScheme.h" CPPUNIT_TEST_SUITE_REGISTRATION( testHttpRequest ); @@ -24,6 +25,24 @@ static Initer ensure_mempools; +/* Test the core constructor: method, scheme, url */ +void +testHttpRequest::testConstructMethodProtocolUrl() +{ + /* a CONNECT url with CONNECT data */ + char * url = xstrdup("foo:46"); + HttpRequest aRequest(METHOD_CONNECT, URLSchemeRegistry::GetInstance().findScheme("NONE"), url); + /* direct construction does not parse */ + u_short expected_port = 0; + CPPUNIT_ASSERT_EQUAL(expected_port, aRequest.port); + CPPUNIT_ASSERT_EQUAL(METHOD_CONNECT, aRequest.method); + CPPUNIT_ASSERT_EQUAL(String(""), String(aRequest.host)); + CPPUNIT_ASSERT_EQUAL(String("foo:46"), aRequest.urlpath); + CPPUNIT_ASSERT_EQUAL(String("NONE"), String(aRequest.scheme->const_str())); + CPPUNIT_ASSERT_EQUAL(String("foo:46"), String(url)); + xfree(url); +} + /* * Test creating an HttpRequest object from a Url and method */ @@ -40,7 +59,7 @@ CPPUNIT_ASSERT_EQUAL(METHOD_GET, aRequest->method); CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->host)); CPPUNIT_ASSERT_EQUAL(String("/bar"), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(PROTO_HTTP, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(String("http"), String(aRequest->scheme->const_str())); CPPUNIT_ASSERT_EQUAL(String("http://foo:90/bar"), String(url)); xfree(url); /* vanilla url, different method */ @@ -51,7 +70,7 @@ CPPUNIT_ASSERT_EQUAL(METHOD_PUT, aRequest->method); CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->host)); CPPUNIT_ASSERT_EQUAL(String("/bar"), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(PROTO_HTTP, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(String("http"), String(aRequest->scheme->const_str())); CPPUNIT_ASSERT_EQUAL(String("http://foo/bar"), String(url)); /* a connect url with non-CONNECT data */ url = xstrdup(":foo/bar"); @@ -66,7 +85,7 @@ CPPUNIT_ASSERT_EQUAL(METHOD_CONNECT, aRequest->method); CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->host)); CPPUNIT_ASSERT_EQUAL(String(""), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(PROTO_NONE, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(String("NONE"), String(aRequest->scheme->const_str())); CPPUNIT_ASSERT_EQUAL(String("foo:45"), String(url)); xfree(url); } @@ -86,7 +105,43 @@ CPPUNIT_ASSERT_EQUAL(METHOD_GET, aRequest->method); CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->host)); CPPUNIT_ASSERT_EQUAL(String("/bar"), aRequest->urlpath); - CPPUNIT_ASSERT_EQUAL(PROTO_HTTP, aRequest->protocol); + CPPUNIT_ASSERT_EQUAL(String("http"), String(aRequest->scheme->const_str())); CPPUNIT_ASSERT_EQUAL(String("http://foo:90/bar"), String(url)); xfree(url); } + +/* + * An HTTPRequest can be asked to start grabbing data for itself. This should + * dispatch through the request protocol. + * + * We test this by creating a URLScheme that records when its startFetch + * method is called - so we can tell it is invoked, and what parameters it + * was given. + */ +class RecordingURLScheme : public URLScheme { +public: + RecordingURLScheme() : URLScheme(NULL, PROTO_NONE), request(NULL), entry(NULL), client_fd(-1){} + void startFetch(HttpRequest *request, StoreEntry *entry, int client_fd) + { + request = request; + entry = entry; + client_fd = client_fd; + } + HttpRequest * request; + StoreEntry * entry; + int client_fd; +}; + +void +testHttpRequest::testStartFetch() +{ + RecordingURLScheme scheme; + HttpRequest request(METHOD_GET, &scheme, "/icons/foo.png"); + StoreEntry * entry = NULL; + int client_fd = -1; + if (0) + request.startFetch(entry, client_fd); + // CPPUNIT_ASSERT_EQUAL(&request, scheme.request); + // CPPUNIT_ASSERT_EQUAL(entry, scheme.entry); + // CPPUNIT_ASSERT_EQUAL(-1, scheme.client_fd); +} === modified file 'src/tests/testHttpRequest.h' --- src/tests/testHttpRequest.h 2006-04-30 13:33:01 +0000 +++ src/tests/testHttpRequest.h 2006-08-24 03:02:19 +0000 @@ -11,15 +11,19 @@ class testHttpRequest : public CPPUNIT_NS::TestFixture { CPPUNIT_TEST_SUITE( testHttpRequest ); + CPPUNIT_TEST( testConstructMethodProtocolUrl ); CPPUNIT_TEST( testCreateFromUrlAndMethod ); CPPUNIT_TEST( testCreateFromUrl ); + CPPUNIT_TEST( testStartFetch ); CPPUNIT_TEST_SUITE_END(); public: protected: + void testConstructMethodProtocolUrl(); void testCreateFromUrlAndMethod(); void testCreateFromUrl(); + void testStartFetch(); }; #endif === modified file 'src/tests/testURL.cc' --- src/tests/testURL.cc 2006-05-08 23:58:04 +0000 +++ src/tests/testURL.cc 2006-08-24 10:24:23 +0000 @@ -37,17 +37,14 @@ } /* - * a default constructed URL has scheme "NONE". - * Also, we should be able to use new and delete on + * We should be able to use new and delete on * scheme instances. */ void -testURL::testDefaultConstructor() +testURL::testNewDelete() { - URL aUrl; - CPPUNIT_ASSERT_EQUAL(URLScheme(), aUrl.getScheme()); - - URL *urlPointer = new URL; + URLScheme aScheme; + URL *urlPointer = new URL(aScheme); CPPUNIT_ASSERT(urlPointer != NULL); delete urlPointer; } === modified file 'src/tests/testURL.h' --- src/tests/testURL.h 2006-05-08 22:48:34 +0000 +++ src/tests/testURL.h 2006-08-24 10:23:24 +0000 @@ -12,7 +12,7 @@ { CPPUNIT_TEST_SUITE( testURL ); CPPUNIT_TEST( testConstructScheme ); - CPPUNIT_TEST( testDefaultConstructor ); + CPPUNIT_TEST( testNewDelete ); CPPUNIT_TEST_SUITE_END(); public: @@ -20,7 +20,7 @@ protected: void testConstructScheme(); - void testDefaultConstructor(); + void testNewDelete(); }; #endif === modified file 'src/tests/testURLScheme.cc' --- src/tests/testURLScheme.cc 2006-05-08 23:58:04 +0000 +++ src/tests/testURLScheme.cc 2006-08-27 23:33:51 +0000 @@ -2,6 +2,7 @@ #include #include +#include "HttpRequest.h" #include "Mem.h" #include "testURLScheme.h" #include "URLScheme.h" @@ -125,12 +126,198 @@ } /* - * we should be able to send it to a stream and get the normalised version + * we should be able to send any URLScheme to a stream and + * get the normalised version of its const_str() */ +class StrangeURLScheme : public URLScheme { +public: + char const * const_str() const { return "strange"; } +}; void testURLScheme::testStream() { std::ostringstream buffer; - buffer << URLScheme(PROTO_HTTP); - CPPUNIT_ASSERT_EQUAL(String("http"), String(buffer.str().c_str())); + buffer << StrangeURLScheme(); + CPPUNIT_ASSERT_EQUAL(String("strange"), String(buffer.str().c_str())); +} + +/* + * url schemes can fetch data. For schemes that require remote data grabbing + * this starts by doing a peer selection. For schemes that have data locally + * it may immediately start delivering content. + * + * There is no test-scenario support for squid at this point, so we need to + * test each URLScheme subclass as they get created. For now, we test that + * the call compiles. + */ +void +testURLScheme::testStartFetch() +{ + URLScheme scheme(PROTO_HTTP); + HttpRequest * request = NULL; + StoreEntry * entry = NULL; + int client_fd = -1; + if (0) + scheme.startFetch(request, entry, client_fd); +} + +/* + * We can register a URLScheme under a string value + */ +class NewScheme : public URLScheme { +public: + char const *const_str() const { return "foobar"; } +}; + +/* the URLSchemeRegistry supports parsing a region of memory to find a scheme. + * + * To test this, we add a new scheme to a clean registry and try to parse it. + * + */ +class ParseTestScheme : public URLScheme { +public: + ParseTestScheme(URLSchemeRegistry & registry) : URLScheme(registry) {} + char const * const_str() const { return "scheme_name"; } +}; + +void +testURLScheme::testFindScheme() +{ + URLSchemeRegistry registry; + ParseTestScheme const scheme(registry); + char const *string_to_parse = "scheme_name:here"; + /* implicit NULL parameter */ + CPPUNIT_ASSERT_EQUAL(dynamic_cast(&scheme), registry.findScheme(string_to_parse)); + /* find the : by heuristic on end == NULL*/ + CPPUNIT_ASSERT_EQUAL(dynamic_cast(&scheme), registry.findScheme(string_to_parse, NULL)); + /* given a prefix match, find nothing: this preventts + * HTT matching HTTP */ + CPPUNIT_ASSERT_EQUAL((URLScheme const *)NULL, registry.findScheme(string_to_parse, string_to_parse + 1)); + /* given a string that does not match, and a supplied end, find nothing */ + CPPUNIT_ASSERT_EQUAL((URLScheme const *)NULL, registry.findScheme(string_to_parse, string_to_parse + 13)); +} +void +testURLScheme::testRegisterProtocol() +{ + URLSchemeRegistry registry; + NewScheme scheme; + registry.registerScheme(&scheme); + CPPUNIT_ASSERT_EQUAL((URLScheme const *)&scheme, registry.findScheme("foobar")); +} + +/* the built in protocols should be registered */ +void +testURLScheme::testDefaultsRegistered() +{ + URLSchemeRegistry ®istry(URLSchemeRegistry::GetInstance()); + CPPUNIT_ASSERT_EQUAL(String("NONE"), + String(registry.findScheme("NONE")->const_str())); + /* and there is a hard coded default to NONE for the registry */ + CPPUNIT_ASSERT_EQUAL(String("NONE"), + String(registry.findScheme("")->const_str())); + CPPUNIT_ASSERT_EQUAL(String("http"), + String(registry.findScheme("http")->const_str())); + CPPUNIT_ASSERT_EQUAL(String("ftp"), + String(registry.findScheme("ftp")->const_str())); + CPPUNIT_ASSERT_EQUAL(String("wais"), + String(registry.findScheme("wais")->const_str())); + CPPUNIT_ASSERT_EQUAL(String("cache_object"), + String(registry.findScheme("cache_object")->const_str())); + CPPUNIT_ASSERT_EQUAL(String("icp"), + String(registry.findScheme("icp")->const_str())); +#if USE_HTCP + CPPUNIT_ASSERT_EQUAL(String("htcp"), + String(registry.findScheme("htcp")->const_str())); +#endif + CPPUNIT_ASSERT_EQUAL(String("whois"), + String(registry.findScheme("whois")->const_str())); + CPPUNIT_ASSERT_EQUAL(String("internal"), + String(registry.findScheme("internal")->const_str())); + CPPUNIT_ASSERT_EQUAL(String("https"), + String(registry.findScheme("https")->const_str())); +} + + +/* we can override the canonicalUrl function */ +class CanonicalTestURL : public URLScheme { +public: + String canonicalUrl(HttpRequest const * request) const { return "foo"; } +}; + +void +testURLScheme::testCanonicalUrl() +{ + URLScheme *scheme = new CanonicalTestURL; + CPPUNIT_ASSERT_EQUAL(String("foo"), scheme->canonicalUrl(NULL)); + delete scheme; +} + +/* we can override the canonicalUrlCleanUncleaned function to include + * canonicalUrlClean, and canonicalUrlClean strips ctrl characters + */ +class CanonicalCleanTestURL : public URLScheme { +public: + String canonicalUrlCleanUncleaned(HttpRequest const * request) const { return "foo\x1e"; } +}; + +void +testURLScheme::testCanonicalUrlClean() +{ + URLScheme *scheme = new CanonicalCleanTestURL; + CPPUNIT_ASSERT_EQUAL(String("foo%1e"), scheme->canonicalUrlClean(NULL)); + delete scheme; +} + +/* nothing to see, but does it compile */ +/* subclass so that we dont depend on a default constructable URLScheme. */ +class CanServeTestScheme : public URLScheme { +}; + +void +testURLScheme::testCanServe() +{ + URLScheme * scheme = new CanServeTestScheme; + if (0) + scheme->canServe(NULL); + delete scheme; +} + +/* URLSchemes may be cachable or not. This may examine the HttpRequest + * to make the decision. Cachability is used in determining whether to try + * using the cache hieararchy or not - uncachable requests are pointless to + * send via the hierarchy. + * + * here we check that we can override the interface safely. + */ +class CachableURLScheme : public URLScheme { + bool cacheable(HttpRequest const *) const { return true;} +}; +class UnCachableURLScheme : public URLScheme { + bool cacheable(HttpRequest const *) const { return false;} +}; +void +testURLScheme::testCacheable() +{ + URLScheme *scheme = new CachableURLScheme; + CPPUNIT_ASSERT_EQUAL(true, scheme->cacheable(NULL)); + delete scheme; + scheme = new UnCachableURLScheme; + CPPUNIT_ASSERT_EQUAL(false, scheme->cacheable(NULL)); + delete scheme; +} + +/* URLSchemes can provide a default port. (Currently they have to, but once + * the parsing and canonicalisation stuff is all factored, it will be optional + * because some schemes dont use that. At that point we should probably consider + * a subclass to reflect that usage, or shuffle the class layout somewhat. + */ +class MyDefaultPortScheme : public URLScheme { + int defaultPort() const { return 1234; } +}; +void +testURLScheme::testDefaultPort() +{ + URLScheme * scheme = new MyDefaultPortScheme; + CPPUNIT_ASSERT_EQUAL(1234, scheme->defaultPort()); + delete scheme; } === modified file 'src/tests/testURLScheme.h' --- src/tests/testURLScheme.h 2006-05-08 23:58:04 +0000 +++ src/tests/testURLScheme.h 2006-08-27 23:26:55 +0000 @@ -12,18 +12,21 @@ { CPPUNIT_TEST_SUITE( testURLScheme ); CPPUNIT_TEST( testAssignFromprotocol_t ); + CPPUNIT_TEST( testCacheable ); + CPPUNIT_TEST( testCanonicalUrl ); + CPPUNIT_TEST( testCanonicalUrlClean ); + CPPUNIT_TEST( testCanServe ); CPPUNIT_TEST( testCastToprotocol_t ); CPPUNIT_TEST( testConstructprotocol_t ); -#if 0 - - CPPUNIT_TEST( testConstructCharStart ); - CPPUNIT_TEST( testConstructCharStartEnd ); -#endif - CPPUNIT_TEST( testDefaultConstructor ); + CPPUNIT_TEST( testDefaultPort ); + CPPUNIT_TEST( testDefaultsRegistered ); CPPUNIT_TEST( testEqualprotocol_t ); CPPUNIT_TEST( testNotEqualprotocol_t ); + CPPUNIT_TEST( testFindScheme ); CPPUNIT_TEST( testConst_str ); + CPPUNIT_TEST( testRegisterProtocol ); + CPPUNIT_TEST( testStartFetch ); CPPUNIT_TEST( testStream ); CPPUNIT_TEST_SUITE_END(); @@ -31,18 +34,21 @@ protected: void testAssignFromprotocol_t(); + void testCacheable(); + void testCanonicalUrl(); + void testCanonicalUrlClean(); + void testCanServe(); void testCastToprotocol_t(); void testConstructprotocol_t(); -#if 0 - - void testConstructCharStart(); - void testConstructCharStartEnd(); -#endif - void testConst_str(); void testDefaultConstructor(); + void testDefaultPort(); + void testDefaultsRegistered(); void testEqualprotocol_t(); void testNotEqualprotocol_t(); + void testFindScheme(); + void testRegisterProtocol(); + void testStartFetch(); void testStream(); }; === modified file 'src/tunnel.cc' --- src/tunnel.cc 2006-08-20 08:59:21 +0000 +++ src/tunnel.cc 2006-08-26 07:07:37 +0000 @@ -45,6 +45,7 @@ #endif #include "client_side.h" #include "MemBuf.h" +#include "neighbors.h" #include "http.h" class SslStateData === modified file 'src/typedefs.h' --- src/typedefs.h 2006-08-21 00:32:38 +0000 +++ src/typedefs.h 2006-08-26 06:40:36 +0000 @@ -230,7 +230,6 @@ typedef void FQDNH(const char *, void *); typedef void IDCB(const char *ident, void *data); typedef void IPH(const ipcache_addrs *, void *); -typedef void IRCB(peer *, peer_t, protocol_t, void *, void *data); class FwdServer; typedef void PSC(FwdServer *, void *); === modified file 'src/url.cc' --- src/url.cc 2006-05-29 21:44:55 +0000 +++ src/url.cc 2006-08-27 23:46:47 +0000 @@ -37,7 +37,6 @@ #include "HttpRequest.h" #include "URLScheme.h" -static HttpRequest *urnParse(method_t method, char *urn); #if CHECK_HOSTNAMES static const char *const valid_hostname_chars = #if ALLOW_HOSTNAME_UNDERSCORES @@ -117,93 +116,6 @@ } /* - * urlParseProtocol() takes begin (b) and end (e) pointers, but for - * backwards compatibility, e defaults to NULL, in which case we - * assume b is NULL-terminated. - */ -protocol_t -urlParseProtocol(const char *b, const char *e) -{ - /* - * if e is NULL, b must be NULL terminated and we - * make e point to the first whitespace character - * after b. - */ - - if (NULL == e) - e = b + strcspn(b, ":"); - - int len = e - b; - - /* test common stuff first */ - - if (strncasecmp(b, "http", len) == 0) - return PROTO_HTTP; - - if (strncasecmp(b, "ftp", len) == 0) - return PROTO_FTP; - - if (strncasecmp(b, "https", len) == 0) - return PROTO_HTTPS; - - if (strncasecmp(b, "file", len) == 0) - return PROTO_FTP; - - if (strncasecmp(b, "gopher", len) == 0) - return PROTO_GOPHER; - - if (strncasecmp(b, "wais", len) == 0) - return PROTO_WAIS; - - if (strncasecmp(b, "cache_object", len) == 0) - return PROTO_CACHEOBJ; - - if (strncasecmp(b, "urn", len) == 0) - return PROTO_URN; - - if (strncasecmp(b, "whois", len) == 0) - return PROTO_WHOIS; - - if (strncasecmp(b, "internal", len) == 0) - return PROTO_INTERNAL; - - return PROTO_NONE; -} - -int -urlDefaultPort(protocol_t p) -{ - switch (p) { - - case PROTO_HTTP: - return 80; - - case PROTO_HTTPS: - return 443; - - case PROTO_FTP: - return 21; - - case PROTO_GOPHER: - return 70; - - case PROTO_WAIS: - return 210; - - case PROTO_CACHEOBJ: - - case PROTO_INTERNAL: - return CACHE_HTTP_PORT; - - case PROTO_WHOIS: - return 43; - - default: - return 0; - } -} - -/* * Parse a URI/URL. * * If the 'request' arg is non-NULL, put parsed values there instead @@ -226,7 +138,7 @@ char *t = NULL; char *q = NULL; int port; - protocol_t protocol = PROTO_NONE; + URLScheme const *scheme = NULL; int l; proto[0] = host[0] = urlpath[0] = login[0] = '\0'; @@ -237,22 +149,34 @@ return NULL; } + /* cleaning this up: we have three conditions: + * CONNECT - no real url + * URN: we want to avoid all the parsing rigamorale + * OTHER: parse it as a regular hierarchical url + * -> first step solution, start the process with a find_scheme call + * then a virtual dispatch to parse it. + */ if (method == METHOD_CONNECT) { port = CONNECT_PORT; if (sscanf(url, "%[^:]:%d", host, &port) < 1) return NULL; + /* protocol is NONE */ + scheme = URLSchemeRegistry::GetInstance().findScheme("NONE"); } else if (!strncmp(url, "urn:", 4)) { - return urnParse(method, url); + debugs(50, 5, "urnParse: " << url); + /* find the urn scheme */ + return new HttpRequest(method, URLSchemeRegistry::GetInstance().findScheme("urn"), url + 4); } else { if (sscanf(url, "%[^:]://%[^/]%[^\r\n]", proto, host, urlpath) < 2) return NULL; - protocol = urlParseProtocol(proto); - - port = urlDefaultPort(protocol); - - /* Is there any login informaiton? */ + scheme = URLSchemeRegistry::GetInstance().findScheme(proto); + /* scheme may be NONE */ + + port = scheme->defaultPort(); + + /* Is there any login information? */ if ((t = strrchr(host, '@'))) { strcpy((char *) login, (char *) host); t = strrchr(login, '@'); @@ -358,9 +282,9 @@ } if (NULL == request) - request = new HttpRequest(method, protocol, urlpath); + request = new HttpRequest(method, scheme, urlpath); else { - request->initHTTP(method, protocol, urlpath); + request->initHTTP(method, scheme, urlpath); } xstrncpy(request->host, host, SQUIDHOSTNAMELEN); @@ -369,107 +293,23 @@ return request; } -static HttpRequest * -urnParse(method_t method, char *urn) -{ - debug(50, 5) ("urnParse: %s\n", urn); - return new HttpRequest(method, PROTO_URN, urn + 4); -} - const char * urlCanonical(HttpRequest * request) { - LOCAL_ARRAY(char, portbuf, 32); - LOCAL_ARRAY(char, urlbuf, MAX_URL); - - if (request->canonical) - return request->canonical; - - if (request->protocol == PROTO_URN) { - snprintf(urlbuf, MAX_URL, "urn:%s", request->urlpath.buf()); - } else { - switch (request->method) { - - case METHOD_CONNECT: - snprintf(urlbuf, MAX_URL, "%s:%d", request->host, request->port); - break; - - default: - portbuf[0] = '\0'; - - if (request->port != urlDefaultPort(request->protocol)) - snprintf(portbuf, 32, ":%d", request->port); - - snprintf(urlbuf, MAX_URL, "%s://%s%s%s%s%s", - ProtocolStr[request->protocol], - request->login, - *request->login ? "@" : null_string, - request->host, - portbuf, - request->urlpath.buf()); - - break; - } - } - - return (request->canonical = xstrdup(urlbuf)); + if (!request->canonical) + /* set the cached value */ + request->canonical = xstrdup(request->scheme->canonicalUrl(request).buf()); + + return request->canonical; } char * urlCanonicalClean(const HttpRequest * request) { LOCAL_ARRAY(char, buf, MAX_URL); - LOCAL_ARRAY(char, portbuf, 32); - LOCAL_ARRAY(char, loginbuf, MAX_LOGIN_SZ + 1); - char *t; - - if (request->protocol == PROTO_URN) { - snprintf(buf, MAX_URL, "urn:%s", request->urlpath.buf()); - } else { - switch (request->method) { - - case METHOD_CONNECT: - snprintf(buf, MAX_URL, "%s:%d", request->host, request->port); - break; - - default: - portbuf[0] = '\0'; - - if (request->port != urlDefaultPort(request->protocol)) - snprintf(portbuf, 32, ":%d", request->port); - - loginbuf[0] = '\0'; - - if ((int) strlen(request->login) > 0) { - strcpy(loginbuf, request->login); - - if ((t = strchr(loginbuf, ':'))) - *t = '\0'; - - strcat(loginbuf, "@"); - } - - snprintf(buf, MAX_URL, "%s://%s%s%s%s", - ProtocolStr[request->protocol], - loginbuf, - request->host, - portbuf, - request->urlpath.buf()); - /* - * strip arguments AFTER a question-mark - */ - - if (Config.onoff.strip_query_terms) - if ((t = strchr(buf, '?'))) - *(++t) = '\0'; - - break; - } - } - - if (stringHasCntl(buf)) - xstrncpy(buf, rfc1738_escape_unescaped(buf), MAX_URL); - + + String result = request->scheme->canonicalUrlClean(request); + xstrncpy(buf, result.buf(), MAX_URL); return buf; } @@ -574,7 +414,6 @@ int urlCheckRequest(const HttpRequest * r) { - int rc = 0; /* protocol "independent" methods * * actually these methods are specific to HTTP: @@ -583,7 +422,7 @@ * there. * * So, we should delegate them to HTTP. The problem is that we - * do not have a default protocol from the client side of HTTP. + * do not have an explicit default protocol from the client side of HTTP. */ if (r->method == METHOD_CONNECT) @@ -595,56 +434,7 @@ if (r->method == METHOD_PURGE) return 1; - /* does method match the protocol? */ - switch (r->protocol) { - - case PROTO_URN: - - case PROTO_HTTP: - - case PROTO_CACHEOBJ: - rc = 1; - break; - - case PROTO_FTP: - - if (r->method == METHOD_PUT) - rc = 1; - - case PROTO_GOPHER: - - case PROTO_WAIS: - - case PROTO_WHOIS: - if (r->method == METHOD_GET) - rc = 1; - else if (r->method == METHOD_HEAD) - rc = 1; - - break; - - case PROTO_HTTPS: -#ifdef USE_SSL - - rc = 1; - - break; - -#else - /* - * Squid can't originate an SSL connection, so it should - * never receive an "https:" URL. It should always be - * CONNECT instead. - */ - rc = 0; - -#endif - - default: - break; - } - - return rc; + return r->scheme->canServe(r); } /* @@ -740,8 +530,5 @@ return Host; } -URL::URL() : scheme() -{} - -URL::URL(URLScheme const &aScheme): scheme(aScheme) +URL::URL(URLScheme const &aScheme): scheme(&aScheme) {} === modified file 'src/urn.cc' --- src/urn.cc 2006-08-20 08:59:21 +0000 +++ src/urn.cc 2006-08-26 03:19:49 +0000 @@ -34,6 +34,7 @@ */ #include "squid.h" +#include "urn.h" #include "errorpage.h" #include "StoreClient.h" #include "Store.h" @@ -43,6 +44,8 @@ #include "forward.h" #include "SquidTime.h" +static URLSchemeURN urn(URLSchemeRegistry::GetInstance()); + #define URN_REQBUF_SZ 4096 class UrnState : public StoreClient @@ -238,6 +241,9 @@ HTTPMSGLOCK(urlres_r); urlres_r->header.putStr(HDR_ACCEPT, "text/plain"); + /* now we will get called back on ->created when the result data starts + * flowing + */ } void @@ -247,9 +253,7 @@ entry = e; request = HTTPMSGLOCK(r); - entry->lock() - - ; + entry->lock(); setUriResFromRequest(r); if (urlres_r == NULL) @@ -286,8 +290,39 @@ this); } +URLSchemeURN::URLSchemeURN() {} +URLSchemeURN::URLSchemeURN(URLSchemeRegistry ®istry) : URLScheme(registry) +{ +} + +String +URLSchemeURN::canonicalUrl(HttpRequest const * request) const +{ + /* urn takes the literal path we were given */ + String result("urn:"); + result.append(request->urlpath); + return result; +} + +String +URLSchemeURN::canonicalUrlCleanUncleaned(HttpRequest const * request) const +{ + /* URN cleaned urls are the same as normal */ + return canonicalUrl(request); +} + +/* any URN url request can be served. + * XXX: I strongly suspect this is faulty! RC 20060826 + */ +bool +URLSchemeURN::canServe(HttpRequest const * request) const +{ + return true; +} + +/* start the fetch process for a URN request. */ void -urnStart(HttpRequest * r, StoreEntry * e) +URLSchemeURN::startFetch(HttpRequest * r, StoreEntry * e, int client_fd) const { UrnState *anUrn = new UrnState(); anUrn->start (r, e);