You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2015/07/19 16:14:43 UTC
[3/8] trafficserver git commit: TS-974: Partial Object Caching.
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/StatSystem.cc
----------------------------------------------------------------------
diff --git a/proxy/StatSystem.cc b/proxy/StatSystem.cc
index 391cdd8..fa4d102 100644
--- a/proxy/StatSystem.cc
+++ b/proxy/StatSystem.cc
@@ -40,7 +40,6 @@
#define SNAP_USAGE_PERIOD HRTIME_SECONDS(2)
-
// variables
#ifdef DEBUG
@@ -65,7 +64,6 @@ int snap_stats_every = 60;
ink_hrtime http_handler_times[MAX_HTTP_HANDLER_EVENTS];
int http_handler_counts[MAX_HTTP_HANDLER_EVENTS];
-
char snap_filename[PATH_NAME_MAX] = DEFAULT_SNAP_FILENAME;
#define DEFAULT_PERSISTENT
@@ -117,7 +115,6 @@ static int non_persistent_stats[] = {
#undef _FOOTER
#undef _D
-
// functions
static int
@@ -372,7 +369,6 @@ stat_callback(Continuation *cont, HTTPHdr *header)
snprintf(result, result_size - 7, "<pre>\n%s", buffer);
}
-
if (!empty) {
StatPageData data;
@@ -425,7 +421,8 @@ initialize_all_global_stats()
if (access(rundir, R_OK | W_OK) == -1) {
Warning("Unable to access() local state directory '%s': %d, %s", (const char *)rundir, errno, strerror(errno));
- Warning(" Please set 'proxy.config.local_state_dir' to allow statistics collection");
+ Warning(" Please set 'proxy.config.local_state_dir' to allow statistics "
+ "collection");
}
REC_ReadConfigString(snap_file, "proxy.config.stats.snap_file", PATH_NAME_MAX);
Layout::relative_to(snap_filename, sizeof(snap_filename), (const char *)rundir, snap_file);
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/TestClusterHash.cc
----------------------------------------------------------------------
diff --git a/proxy/TestClusterHash.cc b/proxy/TestClusterHash.cc
index 73ab208..3663a4d 100644
--- a/proxy/TestClusterHash.cc
+++ b/proxy/TestClusterHash.cc
@@ -28,7 +28,6 @@
#include "Cluster.h"
#include "libts.h"
-
//
// This test function produces the table included
// in Memo.ClusterHash
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/TestPreProc.cc
----------------------------------------------------------------------
diff --git a/proxy/TestPreProc.cc b/proxy/TestPreProc.cc
index 68fef0d..562721c 100644
--- a/proxy/TestPreProc.cc
+++ b/proxy/TestPreProc.cc
@@ -70,7 +70,6 @@ RequestInput::run()
char *buff = m_cb->getWrite(&maxBytes);
unsigned writeBytes = (m_len < maxBytes) ? m_len : maxBytes;
-
writeBytes = ink_strlcpy(buff, m_sp, maxBytes);
m_cb->wrote(writeBytes);
@@ -177,6 +176,5 @@ main()
cout << "Elapsed time for " << lc << "loops is " << elapsedTime << endl;
}
-
return (0);
}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/TestProxy.cc
----------------------------------------------------------------------
diff --git a/proxy/TestProxy.cc b/proxy/TestProxy.cc
index 5d807a0..fcc061f 100644
--- a/proxy/TestProxy.cc
+++ b/proxy/TestProxy.cc
@@ -30,7 +30,6 @@
#include "OneWayMultiTunnel.h"
#include "Cache.h"
-
struct TestProxy : Continuation {
VConnection *vc;
VConnection *vconnection_vector[2];
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/TestSimpleProxy.cc
----------------------------------------------------------------------
diff --git a/proxy/TestSimpleProxy.cc b/proxy/TestSimpleProxy.cc
index 6cc70f1..412df16 100644
--- a/proxy/TestSimpleProxy.cc
+++ b/proxy/TestSimpleProxy.cc
@@ -137,7 +137,6 @@ struct TestProxy : Continuation {
}
};
-
struct TestAccept : Continuation {
int
startEvent(int event, NetVConnection *e)
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/TimeTrace.h
----------------------------------------------------------------------
diff --git a/proxy/TimeTrace.h b/proxy/TimeTrace.h
index 05c1a01..e6445c2 100644
--- a/proxy/TimeTrace.h
+++ b/proxy/TimeTrace.h
@@ -21,7 +21,6 @@
limitations under the License.
*/
-
/****************************************************************************
TimeTrace.h
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/Transform.h
----------------------------------------------------------------------
diff --git a/proxy/Transform.h b/proxy/Transform.h
index 8585fa0..af0dca3 100644
--- a/proxy/Transform.h
+++ b/proxy/Transform.h
@@ -108,5 +108,4 @@ num_chars_for_int(int64_t i)
extern TransformProcessor transformProcessor;
-
#endif /* __TRANSFORM_H__ */
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/UDPAPIClientTest.cc
----------------------------------------------------------------------
diff --git a/proxy/UDPAPIClientTest.cc b/proxy/UDPAPIClientTest.cc
index 88e74a2..ff41f21 100644
--- a/proxy/UDPAPIClientTest.cc
+++ b/proxy/UDPAPIClientTest.cc
@@ -28,7 +28,6 @@
#include <string.h>
#include <arpa/inet.h>
-
char sendBuff[] = "I'm Alive.";
FILE *fp;
@@ -90,7 +89,6 @@ UDPClient_handle_callbacks(TSCont cont, TSEvent event, void *e)
for (int i = 0; i < avail; i++)
fprintf(fp, "%c", *(buf + i));
-
memcpy((char *)&recvBuff + total_len, buf, avail);
TSIOBufferReaderConsume(reader, avail);
total_len += avail;
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/api/ts/InkAPIPrivateIOCore.h
----------------------------------------------------------------------
diff --git a/proxy/api/ts/InkAPIPrivateIOCore.h b/proxy/api/ts/InkAPIPrivateIOCore.h
index 9b7371a..2eea5ee 100644
--- a/proxy/api/ts/InkAPIPrivateIOCore.h
+++ b/proxy/api/ts/InkAPIPrivateIOCore.h
@@ -128,7 +128,6 @@ TSReturnCode sdk_sanity_check_iocore_structure(void *);
tsapi TSMutex TSMutexCreateInternal(void);
tsapi int TSMutexCheck(TSMutex mutex);
-
/* IOBuffer */
tsapi void TSIOBufferReaderCopy(TSIOBufferReader readerp, const void *buf, int64_t length);
tsapi int64_t TSIOBufferBlockDataSizeGet(TSIOBufferBlock blockp);
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/api/ts/remap.h
----------------------------------------------------------------------
diff --git a/proxy/api/ts/remap.h b/proxy/api/ts/remap.h
index c6f3cab..34705cb 100644
--- a/proxy/api/ts/remap.h
+++ b/proxy/api/ts/remap.h
@@ -38,22 +38,26 @@ extern "C" {
typedef struct _tsremap_api_info {
unsigned long size; /* in: sizeof(struct _tsremap_api_info) */
- unsigned long tsremap_version; /* in: TS supported version ((major << 16) | minor) */
+ unsigned long tsremap_version; /* in: TS supported version ((major << 16) |
+ minor) */
} TSRemapInterface;
-
typedef struct _tm_remap_request_info {
- /* Important: You should *not* release these buf pointers or TSMLocs from your plugin! */
+ /* Important: You should *not* release these buf pointers or TSMLocs from your
+ * plugin! */
/* these URL mloc's are read only, use normal ts/ts.h APIs for accesing */
TSMLoc mapFromUrl;
TSMLoc mapToUrl;
- /* the request URL mloc and buffer pointers are read-write. You can read and modify the
- requestUrl using normal ts/ts.h APIs, which is how you change the destination URL. */
+ /* the request URL mloc and buffer pointers are read-write. You can read and
+ modify the
+ requestUrl using normal ts/ts.h APIs, which is how you change the destination
+ URL. */
TSMLoc requestUrl;
- /* requestBufp and requestHdrp are the equivalent of calling TSHttpTxnClientReqGet(). */
+ /* requestBufp and requestHdrp are the equivalent of calling
+ * TSHttpTxnClientReqGet(). */
TSMBuffer requestBufp;
TSMLoc requestHdrp;
@@ -61,7 +65,6 @@ typedef struct _tm_remap_request_info {
int redirect;
} TSRemapRequestInfo;
-
/* This is the type returned by the TSRemapDoRemap() callback */
typedef enum {
TSREMAP_NO_REMAP = 0, /* No remaping was done, continue with next in chain */
@@ -74,13 +77,14 @@ typedef enum {
-500 to -599
....
This would allow a plugin to generate an error page. Right now,
- setting the return code to any negative number is equivalent to TSREMAP_NO_REMAP */
+ setting the return code to any negative number is equivalent to
+ TSREMAP_NO_REMAP */
TSREMAP_ERROR = -1 /* Some error, that should generate an error page */
} TSRemapStatus;
-
/* ----------------------------------------------------------------------------------
- These are the entry points a plugin can implement. Note that TSRemapInit() and
+ These are the entry points a plugin can implement. Note that TSRemapInit()
+ and
TSRemapDoRemap() are both required.
----------------------------------------------------------------------------------
*/
@@ -92,33 +96,33 @@ typedef enum {
*/
tsapi TSReturnCode TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size);
-
/* Remap new request
Mandatory interface function.
Remap API plugin can/should use SDK API function calls inside this function!
return: TSREMAP_NO_REMAP - No remaping was done, continue with next in chain
TSREMAP_DID_REMAP - Remapping was done, continue with next in chain
- TSREMAP_NO_REMAP_STOP - No remapping was done, and stop plugin chain evaluation
- TSREMAP_DID_REMAP_STOP - Remapping was done, but stop plugin chain evaluation
+ TSREMAP_NO_REMAP_STOP - No remapping was done, and stop plugin chain
+ evaluation
+ TSREMAP_DID_REMAP_STOP - Remapping was done, but stop plugin chain
+ evaluation
*/
tsapi TSRemapStatus TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo *rri);
-
/* Plugin shutdown, called when plugin is unloaded.
Optional function. */
tsapi void TSRemapDone(void);
-
-/* Plugin new instance. Create new plugin processing entry for unique remap record.
+/* Plugin new instance. Create new plugin processing entry for unique remap
+ record.
First two arguments in argv vector are - fromURL and toURL from remap record.
- Please keep in mind that fromURL and toURL will be converted to canonical view.
+ Please keep in mind that fromURL and toURL will be converted to canonical
+ view.
Return: TS_SUCESS
TS_ERROR - instance creation error
*/
tsapi TSReturnCode TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_size);
tsapi void TSRemapDeleteInstance(void *);
-
/* Check response code from Origin Server
os_response_type -> TSServerState
Remap API plugin can use InkAPI function calls inside TSRemapDoRemap()
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/api/ts/ts.h
----------------------------------------------------------------------
diff --git a/proxy/api/ts/ts.h b/proxy/api/ts/ts.h
index 779f99c..6453c41 100644
--- a/proxy/api/ts/ts.h
+++ b/proxy/api/ts/ts.h
@@ -729,7 +729,6 @@ TSUrlPercentEncode(TSMBuffer bufp, TSMLoc offset, char *dst, size_t dst_size, si
*/
tsapi TSReturnCode TSStringPercentDecode(const char *str, size_t str_len, char *dst, size_t dst_size, size_t *length);
-
/* --------------------------------------------------------------------------
MIME headers */
@@ -1006,7 +1005,8 @@ tsapi TSReturnCode TSMimeHdrFieldValueUintSet(TSMBuffer bufp, TSMLoc hdr, TSMLoc
tsapi TSReturnCode TSMimeHdrFieldValueDateSet(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, time_t value);
tsapi TSReturnCode TSMimeHdrFieldValueAppend(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, const char *value, int length);
-/* These Insert() APIs should be considered. Use the corresponding Set() API instead */
+/* These Insert() APIs should be considered. Use the corresponding Set() API
+ * instead */
tsapi TSReturnCode
TSMimeHdrFieldValueStringInsert(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, const char *value, int length);
tsapi TSReturnCode TSMimeHdrFieldValueIntInsert(TSMBuffer bufp, TSMLoc hdr, TSMLoc field, int idx, int value);
@@ -1338,7 +1338,8 @@ tsapi struct sockaddr const *TSHttpTxnServerAddrGet(TSHttpTxn txnp);
This must be invoked before the origin server address is looked up.
If called no lookup is done, the address @a addr is used instead.
- @return @c TS_SUCCESS if the origin server address is set, @c TS_ERROR otherwise.
+ @return @c TS_SUCCESS if the origin server address is set, @c TS_ERROR
+ otherwise.
*/
tsapi TSReturnCode TSHttpTxnServerAddrSet(TSHttpTxn txnp, struct sockaddr const *addr /**< Address for origin server. */
);
@@ -1496,8 +1497,10 @@ tsapi void *TSHttpTxnArgGet(TSHttpTxn txnp, int arg_idx);
tsapi void TSHttpSsnArgSet(TSHttpSsn ssnp, int arg_idx, void *arg);
tsapi void *TSHttpSsnArgGet(TSHttpSsn ssnp, int arg_idx);
-/* The reserve API should only be use in TSAPI plugins, during plugin initialization! */
-/* The lookup methods can be used anytime, but are best used during initialization as well,
+/* The reserve API should only be use in TSAPI plugins, during plugin
+ * initialization! */
+/* The lookup methods can be used anytime, but are best used during
+ initialization as well,
or at least "cache" the results for best performance. */
tsapi TSReturnCode TSHttpArgIndexReserve(const char *name, const char *description, int *arg_idx);
tsapi TSReturnCode TSHttpArgIndexNameLookup(const char *name, int *arg_idx, const char **description);
@@ -1534,7 +1537,8 @@ tsapi void TSHttpTxnDebugSet(TSHttpTxn txnp, int on);
tsapi int TSHttpTxnDebugGet(TSHttpTxn txnp);
/**
Set the session specific debugging flag for this client session.
- When turned on, internal debug messages related to this session and all transactions
+ When turned on, internal debug messages related to this session and all
+ transactions
in the session will be written even if the debug tag isn't on.
@param ssnp Client session to change.
@@ -1624,7 +1628,8 @@ tsapi void TSHttpTxnServerIntercept(TSCont contp, TSHttpTxn txnp);
This returns a VConn that connected to the transaction.
@param addr Target address of the origin server.
- @param tag A logging tag that can be accessed via the pitag field. May be @c NULL.
+ @param tag A logging tag that can be accessed via the pitag field. May be @c
+ NULL.
@param id A logging id that can be access via the piid field.
*/
tsapi TSVConn TSHttpConnectWithPluginId(struct sockaddr const *addr, char const *tag, int64_t id);
@@ -1722,10 +1727,10 @@ tsapi struct sockaddr const *TSNetVConnRemoteAddrGet(TSVConn vc);
or cancel the attempt to connect.
*/
-tsapi TSAction
-TSNetConnect(TSCont contp, /**< continuation that is called back when the attempted net connection either succeeds or fails. */
- struct sockaddr const *to /**< Address to which to connect. */
- );
+tsapi TSAction TSNetConnect(TSCont contp, /**< continuation that is called back when the attempted net
+ connection either succeeds or fails. */
+ struct sockaddr const *to /**< Address to which to connect. */
+ );
tsapi TSAction TSNetAccept(TSCont contp, int port, int domain, int accept_threads);
@@ -1947,8 +1952,10 @@ tsapi int64_t TSIOBufferReaderAvail(TSIOBufferReader readerp);
tsapi struct sockaddr const *TSNetVConnLocalAddrGet(TSVConn vc);
/* --------------------------------------------------------------------------
- Stats and configs based on librecords raw stats (this is preferred API until we
- rewrite stats). This system has a limitation of up to 1,500 stats max, controlled
+ Stats and configs based on librecords raw stats (this is preferred API until
+ we
+ rewrite stats). This system has a limitation of up to 1,500 stats max,
+ controlled
via proxy.config.stat_api.max_stats_allowed (default is 512).
This is available as of Apache TS v2.2.*/
@@ -1997,7 +2004,8 @@ tsapi void TSDebug(const char *tag, const char *format_str, ...) TS_PRINTFLIKE(2
Output a debug line even if the debug tag is turned off, as long as
debugging is enabled. Could be used as follows:
@code
- TSDebugSpecifc(TSHttpTxnDebugGet(txn), "plugin_tag" , "Hello World from transaction %p", txn);
+ TSDebugSpecifc(TSHttpTxnDebugGet(txn), "plugin_tag" , "Hello World from
+ transaction %p", txn);
@endcode
will be printed if the plugin_tag is enabled or the transaction specific
debugging is turned on for txn.
@@ -2157,14 +2165,16 @@ tsapi TSReturnCode TSTextLogObjectRollingEnabledSet(TSTextLogObject the_object,
tsapi void TSTextLogObjectRollingIntervalSecSet(TSTextLogObject the_object, int rolling_interval_sec);
/**
- Set the rolling offset. rolling_offset_hr specifies the hour (between 0 and 23) when log rolling
+ Set the rolling offset. rolling_offset_hr specifies the hour (between 0 and
+ 23) when log rolling
should take place.
*/
tsapi void TSTextLogObjectRollingOffsetHrSet(TSTextLogObject the_object, int rolling_offset_hr);
/**
- Set the rolling size. rolling_size_mb specifies the size in MB when log rolling
+ Set the rolling size. rolling_size_mb specifies the size in MB when log
+ rolling
should take place.
*/
@@ -2240,7 +2250,6 @@ tsapi void TSVConnActiveTimeoutCancel(TSVConn connp);
*/
tsapi void TSSkipRemappingSet(TSHttpTxn txnp, int flag);
-
/*
Set or get various overridable configurations, for a transaction. This should
probably be done as early as possible, e.g. TS_HTTP_READ_REQUEST_HDR_HOOK.
@@ -2284,7 +2293,8 @@ tsapi void TSHttpTxnRedirectUrlSet(TSHttpTxn txnp, const char *url, const int ur
tsapi TS_DEPRECATED void TSRedirectUrlSet(TSHttpTxn txnp, const char *url, const int url_len);
/**
- Return the current (if set) redirection URL string. This is still owned by the
+ Return the current (if set) redirection URL string. This is still owned by
+ the
core, and must not be free'd.
@param txnp the transaction pointer
@@ -2327,10 +2337,13 @@ tsapi int TSHttpTxnBackgroundFillStarted(TSHttpTxn txnp);
tsapi TSReturnCode TSBase64Decode(const char *str, size_t str_len, unsigned char *dst, size_t dst_size, size_t *length);
tsapi TSReturnCode TSBase64Encode(const char *str, size_t str_len, char *dst, size_t dst_size, size_t *length);
-/* Get milestone timers, useful for measuring where we are spending time in the transaction processing */
+/* Get milestone timers, useful for measuring where we are spending time in the
+ * transaction processing */
/**
- Return the particular milestone timer for the transaction. If 0 is returned, it means
- the transaction has not yet reached that milestone. Asking for an "unknown" milestone is
+ Return the particular milestone timer for the transaction. If 0 is returned,
+ it means
+ the transaction has not yet reached that milestone. Asking for an "unknown"
+ milestone is
an error.
@param txnp the transaction pointer
@@ -2344,20 +2357,25 @@ tsapi TSReturnCode TSBase64Encode(const char *str, size_t str_len, char *dst, si
tsapi TSReturnCode TSHttpTxnMilestoneGet(TSHttpTxn txnp, TSMilestonesType milestone, TSHRTime *time);
/**
- Test whether a request / response header pair would be cacheable under the current
- configuration. This would typically be used in TS_HTTP_READ_RESPONSE_HDR_HOOK, when
+ Test whether a request / response header pair would be cacheable under the
+ current
+ configuration. This would typically be used in TS_HTTP_READ_RESPONSE_HDR_HOOK,
+ when
you have both the client request and server response ready.
@param txnp the transaction pointer
- @param request the client request header. If NULL, use the transactions client request.
- @param response the server response header. If NULL, use the transactions origin response.
+ @param request the client request header. If NULL, use the transactions client
+ request.
+ @param response the server response header. If NULL, use the transactions
+ origin response.
@return 1 if the request / response is cacheable, 0 otherwise
*/
tsapi int TSHttpTxnIsCacheable(TSHttpTxn txnp, TSMBuffer request, TSMBuffer response);
/**
- Return a string respresentation for a TSServerState value. This is useful for plugin debugging.
+ Return a string respresentation for a TSServerState value. This is useful for
+ plugin debugging.
@param state the value of this TSServerState
@@ -2366,7 +2384,8 @@ tsapi int TSHttpTxnIsCacheable(TSHttpTxn txnp, TSMBuffer request, TSMBuffer resp
tsapi const char *TSHttpServerStateNameLookup(TSServerState state);
/**
- Return a string respresentation for a TSHttpHookID value. This is useful for plugin debugging.
+ Return a string respresentation for a TSHttpHookID value. This is useful for
+ plugin debugging.
@param hook the value of this TSHttpHookID
@@ -2375,7 +2394,8 @@ tsapi const char *TSHttpServerStateNameLookup(TSServerState state);
tsapi const char *TSHttpHookNameLookup(TSHttpHookID hook);
/**
- Return a string respresentation for a TSEvent value. This is useful for plugin debugging.
+ Return a string respresentation for a TSEvent value. This is useful for
+ plugin debugging.
@param event the value of this TSHttpHookID
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/hdrs/HTTP.cc
----------------------------------------------------------------------
diff --git a/proxy/hdrs/HTTP.cc b/proxy/hdrs/HTTP.cc
index 25f14d1..3de7430 100644
--- a/proxy/hdrs/HTTP.cc
+++ b/proxy/hdrs/HTTP.cc
@@ -29,6 +29,7 @@
#include "HTTP.h"
#include "HdrToken.h"
#include "Diags.h"
+#include "I_IOBuffer.h"
/***********************************************************************
* *
@@ -1782,81 +1783,66 @@ ClassAllocator<HTTPCacheAlt> httpCacheAltAllocator("httpCacheAltAllocator");
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
HTTPCacheAlt::HTTPCacheAlt()
- : m_magic(CACHE_ALT_MAGIC_ALIVE), m_writeable(1), m_unmarshal_len(-1), m_id(-1), m_rid(-1), m_request_hdr(), m_response_hdr(),
- m_request_sent_time(0), m_response_received_time(0), m_frag_offset_count(0), m_frag_offsets(0), m_ext_buffer(NULL)
+ : m_magic(CACHE_ALT_MAGIC_ALIVE), m_unmarshal_len(-1), m_id(-1), m_rid(-1), m_frag_count(0), m_request_hdr(), m_response_hdr(),
+ m_request_sent_time(0), m_response_received_time(0), m_fragments(0), m_ext_buffer(NULL)
{
- m_object_key[0] = 0;
- m_object_key[1] = 0;
- m_object_key[2] = 0;
- m_object_key[3] = 0;
- m_object_size[0] = 0;
- m_object_size[1] = 0;
+ m_flags = 0; // set all flags to false.
+ m_flag.writeable_p = true; // except this one.
}
void
HTTPCacheAlt::destroy()
{
ink_assert(m_magic == CACHE_ALT_MAGIC_ALIVE);
- ink_assert(m_writeable);
+ ink_assert(m_flag.writeable_p);
m_magic = CACHE_ALT_MAGIC_DEAD;
- m_writeable = 0;
+ m_flag.writeable_p = 0;
m_request_hdr.destroy();
m_response_hdr.destroy();
- m_frag_offset_count = 0;
- if (m_frag_offsets && m_frag_offsets != m_integral_frag_offsets) {
- ats_free(m_frag_offsets);
- m_frag_offsets = 0;
- }
+ m_frag_count = 0;
+ if (m_flag.table_allocated_p)
+ ats_free(m_fragments);
+ m_fragments = 0;
httpCacheAltAllocator.free(this);
}
void
-HTTPCacheAlt::copy(HTTPCacheAlt *to_copy)
+HTTPCacheAlt::copy(HTTPCacheAlt *that)
{
- m_magic = to_copy->m_magic;
- // m_writeable = to_copy->m_writeable;
- m_unmarshal_len = to_copy->m_unmarshal_len;
- m_id = to_copy->m_id;
- m_rid = to_copy->m_rid;
- m_object_key[0] = to_copy->m_object_key[0];
- m_object_key[1] = to_copy->m_object_key[1];
- m_object_key[2] = to_copy->m_object_key[2];
- m_object_key[3] = to_copy->m_object_key[3];
- m_object_size[0] = to_copy->m_object_size[0];
- m_object_size[1] = to_copy->m_object_size[1];
+ m_magic = that->m_magic;
+ m_unmarshal_len = that->m_unmarshal_len;
+ m_id = that->m_id;
+ m_rid = that->m_rid;
+ m_earliest = that->m_earliest;
- if (to_copy->m_request_hdr.valid()) {
- m_request_hdr.copy(&to_copy->m_request_hdr);
+ if (that->m_request_hdr.valid()) {
+ m_request_hdr.copy(&that->m_request_hdr);
}
- if (to_copy->m_response_hdr.valid()) {
- m_response_hdr.copy(&to_copy->m_response_hdr);
+ if (that->m_response_hdr.valid()) {
+ m_response_hdr.copy(&that->m_response_hdr);
}
- m_request_sent_time = to_copy->m_request_sent_time;
- m_response_received_time = to_copy->m_response_received_time;
- this->copy_frag_offsets_from(to_copy);
-}
+ m_request_sent_time = that->m_request_sent_time;
+ m_response_received_time = that->m_response_received_time;
+ m_fixed_fragment_size = that->m_fixed_fragment_size;
-void
-HTTPCacheAlt::copy_frag_offsets_from(HTTPCacheAlt *src)
-{
- m_frag_offset_count = src->m_frag_offset_count;
- if (m_frag_offset_count > 0) {
- if (m_frag_offset_count > N_INTEGRAL_FRAG_OFFSETS) {
- /* Mixed feelings about this - technically we don't need it to be a
- power of two when copied because currently that means it is frozen.
- But that could change later and it would be a nasty bug to find.
- So we'll do it for now. The relative overhead is tiny.
- */
- int bcount = HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS * 2;
- while (bcount < m_frag_offset_count)
- bcount *= 2;
- m_frag_offsets = static_cast<FragOffset *>(ats_malloc(sizeof(FragOffset) * bcount));
- } else {
- m_frag_offsets = m_integral_frag_offsets;
- }
- memcpy(m_frag_offsets, src->m_frag_offsets, sizeof(FragOffset) * m_frag_offset_count);
+ m_frag_count = that->m_frag_count;
+
+ if (m_flag.table_allocated_p)
+ ats_free(m_fragments);
+
+ // Safe to copy now, and we need to do that before we copy the fragment table.
+ m_flags = that->m_flags;
+
+ if (that->m_fragments) {
+ size_t size = FragmentDescriptorTable::calc_size(that->m_fragments->m_n);
+ m_fragments = static_cast<FragmentDescriptorTable *>(ats_malloc(size));
+ memcpy(m_fragments, that->m_fragments, size);
+ m_flag.table_allocated_p = true;
+ } else {
+ m_fragments = 0;
+ m_flag.table_allocated_p = false;
}
}
@@ -1871,7 +1857,7 @@ HTTPInfo::create()
void
HTTPInfo::copy(HTTPInfo *hi)
{
- if (m_alt && m_alt->m_writeable) {
+ if (m_alt && m_alt->m_flag.writeable_p) {
destroy();
}
@@ -1879,14 +1865,6 @@ HTTPInfo::copy(HTTPInfo *hi)
m_alt->copy(hi->m_alt);
}
-void
-HTTPInfo::copy_frag_offsets_from(HTTPInfo *src)
-{
- if (m_alt && src->m_alt)
- m_alt->copy_frag_offsets_from(src->m_alt);
-}
-
-
int
HTTPInfo::marshal_length()
{
@@ -1900,10 +1878,8 @@ HTTPInfo::marshal_length()
len += m_alt->m_response_hdr.m_heap->marshal_length();
}
- if (m_alt->m_frag_offset_count > HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS) {
- len -= sizeof(m_alt->m_integral_frag_offsets);
- len += sizeof(FragOffset) * m_alt->m_frag_offset_count;
- }
+ if (m_alt->m_fragments)
+ len += FragmentDescriptorTable::calc_size(m_alt->m_fragments->m_n);
return len;
}
@@ -1916,42 +1892,30 @@ HTTPInfo::marshal(char *buf, int len)
HTTPCacheAlt *marshal_alt = (HTTPCacheAlt *)buf;
// non-zero only if the offsets are external. Otherwise they get
// marshalled along with the alt struct.
- int frag_len = (0 == m_alt->m_frag_offset_count || m_alt->m_frag_offsets == m_alt->m_integral_frag_offsets) ?
- 0 :
- sizeof(HTTPCacheAlt::FragOffset) * m_alt->m_frag_offset_count;
+ size_t frag_len = m_alt->m_fragments ? FragmentDescriptorTable::calc_size(m_alt->m_fragments->m_n) : 0;
ink_assert(m_alt->m_magic == CACHE_ALT_MAGIC_ALIVE);
// Make sure the buffer is aligned
// ink_assert(((intptr_t)buf) & 0x3 == 0);
- // If we have external fragment offsets, copy the initial ones
- // into the integral data.
- if (frag_len) {
- memcpy(m_alt->m_integral_frag_offsets, m_alt->m_frag_offsets, sizeof(m_alt->m_integral_frag_offsets));
- frag_len -= sizeof(m_alt->m_integral_frag_offsets);
- // frag_len should never be non-zero at this point, as the offsets
- // should be external only if too big for the internal table.
- }
// Memcpy the whole object so that we can use it
// live later. This involves copying a few
// extra bytes now but will save copying any
// bytes on the way out of the cache
memcpy(buf, m_alt, sizeof(HTTPCacheAlt));
marshal_alt->m_magic = CACHE_ALT_MAGIC_MARSHALED;
- marshal_alt->m_writeable = 0;
+ marshal_alt->m_flag.writeable_p = 0;
marshal_alt->m_unmarshal_len = -1;
marshal_alt->m_ext_buffer = NULL;
buf += HTTP_ALT_MARSHAL_SIZE;
used += HTTP_ALT_MARSHAL_SIZE;
if (frag_len > 0) {
- marshal_alt->m_frag_offsets = static_cast<FragOffset *>(reinterpret_cast<void *>(used));
- memcpy(buf, m_alt->m_frag_offsets + HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS, frag_len);
+ marshal_alt->m_fragments = static_cast<FragmentDescriptorTable *>(reinterpret_cast<void *>(used));
+ memcpy(buf, m_alt->m_fragments, frag_len);
buf += frag_len;
used += frag_len;
- } else {
- marshal_alt->m_frag_offsets = 0;
}
// The m_{request,response}_hdr->m_heap pointers are converted
@@ -1993,7 +1957,6 @@ HTTPInfo::unmarshal(char *buf, int len, RefCountObj *block_ref)
if (alt->m_magic == CACHE_ALT_MAGIC_ALIVE) {
// Already unmarshaled, must be a ram cache
- // it
ink_assert(alt->m_unmarshal_len > 0);
ink_assert(alt->m_unmarshal_len <= len);
return alt->m_unmarshal_len;
@@ -2004,31 +1967,14 @@ HTTPInfo::unmarshal(char *buf, int len, RefCountObj *block_ref)
ink_assert(alt->m_unmarshal_len < 0);
alt->m_magic = CACHE_ALT_MAGIC_ALIVE;
- ink_assert(alt->m_writeable == 0);
+ ink_assert(alt->m_flag.writeable_p == 0);
len -= HTTP_ALT_MARSHAL_SIZE;
- if (alt->m_frag_offset_count > HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS) {
- // stuff that didn't fit in the integral slots.
- int extra = sizeof(FragOffset) * alt->m_frag_offset_count - sizeof(alt->m_integral_frag_offsets);
- char *extra_src = buf + reinterpret_cast<intptr_t>(alt->m_frag_offsets);
- // Actual buffer size, which must be a power of two.
- // Well, technically not, because we never modify an unmarshalled fragment
- // offset table, but it would be a nasty bug should that be done in the
- // future.
- int bcount = HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS * 2;
-
- while (bcount < alt->m_frag_offset_count)
- bcount *= 2;
- alt->m_frag_offsets =
- static_cast<FragOffset *>(ats_malloc(bcount * sizeof(FragOffset))); // WRONG - must round up to next power of 2.
- memcpy(alt->m_frag_offsets, alt->m_integral_frag_offsets, sizeof(alt->m_integral_frag_offsets));
- memcpy(alt->m_frag_offsets + HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS, extra_src, extra);
- len -= extra;
- } else if (alt->m_frag_offset_count > 0) {
- alt->m_frag_offsets = alt->m_integral_frag_offsets;
- } else {
- alt->m_frag_offsets = 0; // should really already be zero.
+ if (alt->m_fragments) {
+ alt->m_fragments = reinterpret_cast<FragmentDescriptorTable *>(buf + reinterpret_cast<intptr_t>(alt->m_fragments));
+ len -= FragmentDescriptorTable::calc_size(alt->m_fragments->m_n);
}
+ alt->m_flag.table_allocated_p = false;
HdrHeap *heap = (HdrHeap *)(alt->m_request_hdr.m_heap ? (buf + (intptr_t)alt->m_request_hdr.m_heap) : 0);
HTTPHdrImpl *hh = NULL;
@@ -2044,6 +1990,7 @@ HTTPInfo::unmarshal(char *buf, int len, RefCountObj *block_ref)
alt->m_request_hdr.m_http = hh;
alt->m_request_hdr.m_mime = hh->m_fields_impl;
alt->m_request_hdr.m_url_cached.m_heap = heap;
+ alt->m_request_hdr.mark_target_dirty();
}
heap = (HdrHeap *)(alt->m_response_hdr.m_heap ? (buf + (intptr_t)alt->m_response_hdr.m_heap) : 0);
@@ -2058,6 +2005,7 @@ HTTPInfo::unmarshal(char *buf, int len, RefCountObj *block_ref)
alt->m_response_hdr.m_heap = heap;
alt->m_response_hdr.m_http = hh;
alt->m_response_hdr.m_mime = hh->m_fields_impl;
+ alt->m_response_hdr.mark_target_dirty();
}
alt->m_unmarshal_len = orig_len - len;
@@ -2078,7 +2026,7 @@ HTTPInfo::check_marshalled(char *buf, int len)
return false;
}
- if (alt->m_writeable != false) {
+ if (alt->m_flag.writeable_p != false) {
return false;
}
@@ -2167,22 +2115,632 @@ HTTPInfo::get_handle(char *buf, int len)
return -1;
}
+HTTPInfo::FragmentDescriptor *
+HTTPInfo::force_frag_at(unsigned int idx)
+{
+ FragmentDescriptor *frag;
+ FragmentDescriptorTable *old_table = 0;
+
+ ink_assert(m_alt);
+ ink_assert(idx >= 0);
+
+ if (0 == idx)
+ return &m_alt->m_earliest;
+
+ if (0 == m_alt->m_fragments || idx > m_alt->m_fragments->m_n) { // no room at the inn
+ int64_t obj_size = this->object_size_get();
+ uint32_t ff_size = this->get_frag_fixed_size();
+ unsigned int n = 0; // set if we need to allocate, this is max array index needed.
+
+ ink_assert(ff_size);
+
+ if (0 == m_alt->m_fragments && obj_size > 0) {
+ n = (obj_size + ff_size - 1) / ff_size;
+ if (idx > n)
+ n = idx;
+ if (!m_alt->m_earliest.m_flag.cached_p)
+ ++n; // going to have an empty earliest fragment.
+ } else {
+ n = idx + MAX(4, idx >> 1); // grow by 50% and at least 4
+ old_table = m_alt->m_fragments;
+ }
+
+ size_t size = FragmentDescriptorTable::calc_size(n);
+ size_t old_size = 0;
+ unsigned int old_count = 0;
+ int64_t offset = 0;
+ CryptoHash key;
+
+ m_alt->m_fragments = static_cast<FragmentDescriptorTable *>(ats_malloc(size));
+ ink_zero(*(m_alt->m_fragments)); // just need to zero the base struct.
+ if (old_table) {
+ old_count = old_table->m_n;
+ frag = &((*old_table)[old_count]);
+ offset = frag->m_offset;
+ key = frag->m_key;
+ old_size = FragmentDescriptorTable::calc_size(old_count);
+ memcpy(m_alt->m_fragments, old_table, old_size);
+ if (m_alt->m_flag.table_allocated_p)
+ ats_free(old_table);
+ } else {
+ key = m_alt->m_earliest.m_key;
+ m_alt->m_fragments->m_cached_idx = 0;
+ }
+ m_alt->m_fragments->m_n = n;
+ m_alt->m_flag.table_allocated_p = true;
+ // fill out the new parts with offsets & keys.
+ ++old_count; // left as the index of the last frag in the previous set.
+ for (frag = &((*m_alt->m_fragments)[old_count]); old_count <= n; ++old_count, ++frag) {
+ key.next();
+ offset += ff_size;
+ frag->m_key = key;
+ frag->m_offset = offset;
+ frag->m_flags = 0;
+ }
+ }
+ ink_assert(idx > m_alt->m_fragments->m_cached_idx);
+ return &(*m_alt->m_fragments)[idx];
+}
+
void
-HTTPInfo::push_frag_offset(FragOffset offset)
+HTTPInfo::mark_frag_write(unsigned int idx)
{
ink_assert(m_alt);
- if (0 == m_alt->m_frag_offsets) {
- m_alt->m_frag_offsets = m_alt->m_integral_frag_offsets;
- } else if (m_alt->m_frag_offset_count >= HTTPCacheAlt::N_INTEGRAL_FRAG_OFFSETS &&
- 0 == (m_alt->m_frag_offset_count & (m_alt->m_frag_offset_count - 1))) {
- // need more space than in integral storage and we're at an upgrade
- // size (power of 2).
- FragOffset *nf = static_cast<FragOffset *>(ats_malloc(sizeof(FragOffset) * (m_alt->m_frag_offset_count * 2)));
- memcpy(nf, m_alt->m_frag_offsets, sizeof(FragOffset) * m_alt->m_frag_offset_count);
- if (m_alt->m_frag_offsets != m_alt->m_integral_frag_offsets)
- ats_free(m_alt->m_frag_offsets);
- m_alt->m_frag_offsets = nf;
+ ink_assert(idx >= 0);
+
+ if (idx >= m_alt->m_frag_count)
+ m_alt->m_frag_count = idx + 1;
+
+ if (0 == idx) {
+ m_alt->m_earliest.m_flag.cached_p = true;
+ } else {
+ this->force_frag_at(idx)->m_flag.cached_p = true;
+ }
+
+ // bump the last cached value if possible and mark complete if appropriate.
+ if (m_alt->m_fragments && idx == m_alt->m_fragments->m_cached_idx + 1) {
+ unsigned int j = idx + 1;
+ while (j < m_alt->m_frag_count && (*m_alt->m_fragments)[j].m_flag.cached_p)
+ ++j;
+ m_alt->m_fragments->m_cached_idx = j - 1;
+ if (!m_alt->m_flag.content_length_p &&
+ (this->get_frag_fixed_size() + this->get_frag_offset(j - 1)) > static_cast<int64_t>(m_alt->m_earliest.m_offset))
+ m_alt->m_flag.complete_p = true;
+ }
+}
+
+int
+HTTPInfo::get_frag_index_of(int64_t offset)
+{
+ int zret = 0;
+ uint32_t ff_size = this->get_frag_fixed_size();
+ FragmentDescriptorTable *table = this->get_frag_table();
+ if (!table) {
+ // Never the case that we have an empty earliest fragment *and* no frag table.
+ zret = offset / ff_size;
+ } else {
+ FragmentDescriptorTable &frags = *table; // easier to work with.
+ int n = frags.m_n; // also the max valid frag table index and always >= 1.
+ // I should probably make @a m_offset int64_t to avoid casting issues like this...
+ uint64_t uoffset = static_cast<uint64_t>(offset);
+
+ if (uoffset >= frags[n].m_offset) {
+ // in or past the last fragment, compute the index by computing the # of @a ff_size chunks past the end.
+ zret = n + (static_cast<uint64_t>(offset) - frags[n].m_offset) / ff_size;
+ } else if (uoffset < frags[1].m_offset) {
+ zret = 0; // in the earliest fragment.
+ } else {
+ // Need to handle old data where the offsets are not guaranteed to be regular.
+ // So we start with our guess (which should be close) and if we're right, boom, else linear
+ // search which should only be 1 or 2 steps.
+ zret = offset / ff_size;
+ if (frags[1].m_offset == 0 || 0 == zret) // zret can be zero if the earliest frag is less than @a ff_size
+ ++zret;
+ while (0 < zret && zret < n) {
+ if (uoffset < frags[zret].m_offset) {
+ --zret;
+ } else if (uoffset >= frags[zret + 1].m_offset) {
+ ++zret;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ return zret;
+}
+/***********************************************************************
+ * *
+ * R A N G E S U P P O R T *
+ * *
+ ***********************************************************************/
+
+namespace
+{
+// Need to promote this out of here at some point.
+// This handles parsing an integer from a string with various limits and in 64 bits.
+struct integer {
+ static size_t const MAX_DIGITS = 15;
+ static bool
+ parse(ts::ConstBuffer const &b, uint64_t &result)
+ {
+ bool zret = false;
+ if (0 < b.size() && b.size() <= MAX_DIGITS) {
+ size_t n;
+ result = ats_strto64(b.data(), b.size(), &n);
+ zret = n == b.size();
+ }
+ return zret;
+ }
+};
+}
+
+bool
+HTTPRangeSpec::parseRangeFieldValue(char const *v, int len)
+{
+ // Maximum # of digits permitted for an offset. Avoid issues with overflow.
+ static size_t const MAX_DIGITS = 15;
+ ts::ConstBuffer src(v, len);
+ size_t n;
+
+ _state = INVALID;
+ src.skip(&ParseRules::is_ws);
+
+ if (src.size() > sizeof(HTTP_LEN_BYTES) + 1 && 0 == strncasecmp(src.data(), HTTP_VALUE_BYTES, HTTP_LEN_BYTES) &&
+ '=' == src[HTTP_LEN_BYTES]) {
+ src += HTTP_LEN_BYTES + 1;
+ while (src) {
+ ts::ConstBuffer max = src.splitOn(',');
+
+ if (!max) { // no comma so everything in @a src should be processed as a single range.
+ max = src;
+ src.reset();
+ }
+
+ ts::ConstBuffer min = max.splitOn('-');
+
+ src.skip(&ParseRules::is_ws);
+ // Spec forbids whitespace anywhere in the range element.
+
+ if (min) {
+ if (ParseRules::is_digit(*min) && min.size() <= MAX_DIGITS) {
+ uint64_t low = ats_strto64(min.data(), min.size(), &n);
+ if (n < min.size())
+ break; // extra cruft in range, not even ws allowed
+ if (max) {
+ if (ParseRules::is_digit(*max) && max.size() <= MAX_DIGITS) {
+ uint64_t high = ats_strto64(max.data(), max.size(), &n);
+ if (n < max.size() && (max += n).skip(&ParseRules::is_ws))
+ break; // non-ws cruft after maximum
+ else
+ this->add(low, high);
+ } else {
+ break; // invalid characters for maximum
+ }
+ } else {
+ this->add(low, UINT64_MAX); // "X-" : "offset X to end of content"
+ }
+ } else {
+ break; // invalid characters for minimum
+ }
+ } else {
+ if (max) {
+ if (ParseRules::is_digit(*max) && max.size() <= MAX_DIGITS) {
+ uint64_t high = ats_strto64(max.data(), max.size(), &n);
+ if (n < max.size() && (max += n).skip(&ParseRules::is_ws)) {
+ break; // cruft after end of maximum
+ } else {
+ this->add(high, 0);
+ }
+ } else {
+ break; // invalid maximum
+ }
+ }
+ }
+ }
+ if (src)
+ _state = INVALID; // didn't parse everything, must have been an error.
+ }
+ return _state != INVALID;
+}
+
+HTTPRangeSpec &
+HTTPRangeSpec::add(Range const &r)
+{
+ if (MULTI == _state) {
+ _ranges.push_back(r);
+ } else if (SINGLE == _state) {
+ _ranges.push_back(_single);
+ _ranges.push_back(r);
+ _state = MULTI;
+ } else {
+ _single = r;
+ _state = SINGLE;
+ }
+ return *this;
+}
+
+bool
+HTTPRangeSpec::apply(uint64_t len)
+{
+ if (!this->hasRanges()) {
+ // nothing - simplifying later logic.
+ } else if (0 == len) {
+ /* Must special case zero length content
+ - suffix ranges are OK but other ranges are not.
+ - Best option is to return a 200 (not 206 or 416) for all suffix range spec on zero length content.
+ (this is what Apache HTTPD does)
+ - So, mark result as either @c UNSATISFIABLE or @c EMPTY, clear all ranges.
+ */
+ _state = EMPTY;
+ if (!_single.isSuffix())
+ _state = UNSATISFIABLE;
+ for (RangeBox::iterator spot = _ranges.begin(), limit = _ranges.end(); spot != limit && EMPTY == _state; ++spot) {
+ if (!spot->isSuffix())
+ _state = UNSATISFIABLE;
+ }
+ _ranges.clear();
+ } else if (this->isSingle()) {
+ if (!_single.apply(len))
+ _state = UNSATISFIABLE;
+ } else { // gotta be MULTI
+ int src = 0, dst = 0;
+ int n = _ranges.size();
+ while (src < n) {
+ Range &r = _ranges[src];
+ if (r.apply(len)) {
+ if (src != dst)
+ _ranges[dst] = r;
+ ++dst;
+ }
+ ++src;
+ }
+ // at this point, @a dst is the # of valid ranges.
+ if (dst > 0) {
+ _single = _ranges[0];
+ if (dst == 1)
+ _state = SINGLE;
+ _ranges.resize(dst);
+ } else {
+ _state = UNSATISFIABLE;
+ _ranges.clear();
+ }
+ }
+ return this->isValid();
+}
+
+static ts::ConstBuffer const MULTIPART_BYTERANGE("multipart/byteranges", 20);
+static ts::ConstBuffer const MULTIPART_BOUNDARY("boundary", 9);
+
+int64_t
+HTTPRangeSpec::parseContentRangeFieldValue(char const *v, int len, Range &r, ts::ConstBuffer &boundary)
+{
+ // [amc] TBD - handle the multipart/byteranges syntax.
+ ts::ConstBuffer src(v, len);
+ int64_t zret = -1;
+
+ r.invalidate();
+ src.skip(&ParseRules::is_ws);
+
+ if (src.skipNoCase(MULTIPART_BYTERANGE)) {
+ while (src && (';' == *src || ParseRules::is_ws(*src)))
+ ++src;
+ if (src.skipNoCase(MULTIPART_BOUNDARY)) {
+ src.trim(&ParseRules::is_ws);
+ boundary = src;
+ }
+ } else if (src.size() > sizeof(HTTP_LEN_BYTES) + 1 && 0 == strncasecmp(src.data(), HTTP_VALUE_BYTES, HTTP_LEN_BYTES) &&
+ ParseRules::is_ws(src[HTTP_LEN_BYTES]) // must have white space
+ ) {
+ uint64_t cl, low, high;
+ bool unsatisfied_p = false, indeterminate_p = false;
+ ts::ConstBuffer min, max;
+
+ src += HTTP_LEN_BYTES;
+ src.skip(&ParseRules::is_ws); // but can have any number
+
+ max = src.splitOn('/'); // src has total length value
+
+ if (max.size() == 1 && *max == '*')
+ unsatisfied_p = true;
+ else
+ min = max.splitOn('-');
+
+ src.trim(&ParseRules::is_ws);
+ if (src && src.size() == 1 && *src == '*')
+ indeterminate_p = true;
+
+ // note - spec forbids internal spaces so it's "X-Y/Z" w/o whitespace.
+ // spec also says we can have "*/Z" or "X-Y/*" but never "*/*".
+
+ if (!(indeterminate_p && unsatisfied_p) && (indeterminate_p || integer::parse(src, cl)) &&
+ (unsatisfied_p || (integer::parse(min, low) && integer::parse(max, high)))) {
+ if (!unsatisfied_p)
+ r._min = low, r._max = high;
+ if (!indeterminate_p)
+ zret = static_cast<int64_t>(cl);
+ }
+ }
+ return zret;
+}
+
+namespace
+{
+int
+Calc_Digital_Length(uint64_t x)
+{
+ char buff[32]; // big enough for 64 bit #
+ return snprintf(buff, sizeof(buff), "%" PRIu64, x);
+}
+}
+
+uint64_t
+HTTPRangeSpec::calcPartBoundarySize(uint64_t object_size, uint64_t ct_val_len)
+{
+ size_t l_size = Calc_Digital_Length(object_size);
+ // CR LF "--" boundary-string CR LF "Content-Range" ": " "bytes " X "-" Y "/" Z CR LF Content-Type CR LF
+ uint64_t zret =
+ 4 + HTTP_RANGE_BOUNDARY_LEN + 2 + MIME_LEN_CONTENT_RANGE + 2 + HTTP_LEN_BYTES + 1 + l_size + 1 + l_size + 1 + l_size + 2;
+ if (ct_val_len)
+ zret += MIME_LEN_CONTENT_TYPE + 2 + ct_val_len + 2;
+ return zret;
+}
+
+uint64_t
+HTTPRangeSpec::calcContentLength(uint64_t object_size, uint64_t ct_val_len) const
+{
+ uint64_t size = object_size;
+ size_t nr = this->count();
+
+ if (nr >= 1) {
+ size = this->size(); // the real content size.
+ if (nr > 1) // part boundaries
+ size += nr * self::calcPartBoundarySize(object_size, ct_val_len) + 2; // need trailing '--'
+ }
+ return size;
+}
+
+uint64_t
+HTTPRangeSpec::writePartBoundary(MIOBuffer *out, char const *boundary_str, size_t boundary_len, uint64_t total_size, uint64_t low,
+ uint64_t high, MIMEField *ctf, bool final)
+{
+ size_t x; // tmp for printf results.
+ size_t loc_size = Calc_Digital_Length(total_size) * 3 + 3; // precomputed size of all the location / size text.
+ size_t n = self::calcPartBoundarySize(total_size, ctf ? ctf->m_len_value : 0) + (final ? 2 : 0);
+ Ptr<IOBufferData> d(new_IOBufferData(iobuffer_size_to_index(n, MAX_BUFFER_SIZE_INDEX), MEMALIGNED));
+ char *spot = d->data();
+
+ x = snprintf(spot, n, "\r\n--%.*s", static_cast<int>(boundary_len), boundary_str);
+ spot += x;
+ n -= x;
+ if (final) {
+ memcpy(spot, "--", 2);
+ spot += 2;
+ n -= 2;
+ }
+
+ x = snprintf(spot, n, "\r\n%.*s: %.*s", MIME_LEN_CONTENT_RANGE, MIME_FIELD_CONTENT_RANGE, HTTP_LEN_BYTES, HTTP_VALUE_BYTES);
+ spot += x;
+ n -= x;
+ spot[-HTTP_LEN_BYTES] = tolower(spot[-HTTP_LEN_BYTES]); // ugly cleanup just to be careful of stupid user agents.
+
+ x = snprintf(spot, n, " %" PRIu64 "-%" PRIu64 "/%" PRIu64, low, high, total_size);
+ // Need to space fill to match pre-computed size
+ if (x < loc_size)
+ memset(spot + x, ' ', loc_size - x);
+ spot += loc_size;
+ n -= loc_size;
+
+ if (ctf) {
+ int ctf_len;
+ char const *ctf_val = ctf->value_get(&ctf_len);
+ if (ctf_val) {
+ x = snprintf(spot, n, "\r\n%.*s: %.*s", MIME_LEN_CONTENT_TYPE, MIME_FIELD_CONTENT_TYPE, ctf_len, ctf_val);
+ spot += x;
+ n -= x;
+ }
+ }
+
+ // This also takes care of the snprintf null termination problem.
+ *spot++ = '\r';
+ *spot++ = '\n';
+ n -= 2;
+
+ ink_assert(n == 0);
+
+ IOBufferBlock *b = new_IOBufferBlock(d, spot - d->data());
+ b->_buf_end = b->_end;
+ out->append_block(b);
+
+ return spot - d->data();
+}
+
+int
+HTTPRangeSpec::print_array(char *buff, size_t len, Range const *rv, int count)
+{
+ size_t zret = 0;
+ bool first = true;
+
+ // Can't possibly write a range in less than this size buffer.
+ if (len < static_cast<size_t>(HTTP_LEN_BYTES) + 4)
+ return 0;
+
+ for (int i = 0; i < count; ++i) {
+ int n;
+
+ if (first) {
+ memcpy(buff, HTTP_VALUE_BYTES, HTTP_LEN_BYTES);
+ buff[HTTP_LEN_BYTES] = '=';
+ zret += HTTP_LEN_BYTES + 1;
+ first = false;
+ } else if (len < zret + 4) {
+ break;
+ } else {
+ buff[zret++] = ',';
+ }
+
+ n = snprintf(buff + zret, len - zret, "%" PRIu64 "-%" PRIu64, rv[i]._min, rv[i]._max);
+ if (n + zret >= len)
+ break; // ran out of room
+ else
+ zret += n;
+ }
+ return zret;
+}
+
+int
+HTTPRangeSpec::print(char *buff, size_t len) const
+{
+ return this->hasRanges() ? this->print_array(buff, len, &(*(this->begin())), this->count()) : 0;
+}
+
+int
+HTTPRangeSpec::print_quantized(char *buff, size_t len, int64_t quantum, int64_t interstitial) const
+{
+ static const int MAX_R = 20; // this needs to be promoted
+ // We will want to have a max # of ranges limit, probably a build time constant, in the not so distant
+ // future anyway, so might as well start here.
+ int qrn = 0; // count of quantized ranges
+ Range qr[MAX_R]; // quantized ranges
+
+ // Can't possibly write a range in less than this size buffer.
+ if (len < static_cast<size_t>(HTTP_LEN_BYTES) + 4)
+ return 0;
+
+ // Avoid annoying "+1" in the adjacency checks.
+ if (interstitial < 1)
+ interstitial = 1;
+ else
+ ++interstitial;
+
+ for (const_iterator spot = this->begin(), limit = this->end(); spot != limit; ++spot) {
+ Range r(*spot);
+ int i;
+ if (quantum > 1) {
+ r._min = (r._min / quantum) * quantum;
+ r._max = ((r._max + quantum - 1) / quantum) * quantum - 1;
+ }
+ // blend in to the current ranges
+ for (i = 0; i < qrn; ++i) {
+ Range &cr = qr[i];
+ if ((r._max + interstitial) < cr._min) {
+ memmove(qr, qr + 1, sizeof(*qr) * qrn);
+ ++qrn;
+ qr[0] = r;
+ i = -1;
+ break;
+ } else if (cr._max + interstitial >= r._min) {
+ int j = i + 1;
+ cr._min = std::min(cr._min, r._min);
+ cr._max = std::max(cr._max, r._max);
+ while (j < qrn) {
+ if (qr[j]._min < cr._max + interstitial)
+ cr._max = std::max(cr._max, qr[j]._max);
+ ++j;
+ }
+ if (j < qrn)
+ memmove(qr + i + 1, qr + j, sizeof(*qr) * qrn - j);
+ qrn -= j - i;
+ i = -1;
+ break;
+ }
+ }
+ if (i >= qrn)
+ qr[qrn++] = r;
+ ink_assert(qrn <= MAX_R);
+ }
+
+ return this->print_array(buff, len, qr, qrn);
+}
+
+HTTPRangeSpec::Range
+HTTPInfo::get_range_for_frags(int low, int high)
+{
+ HTTPRangeSpec::Range zret;
+ zret._min = low < 1 ? 0 : (*m_alt->m_fragments)[low].m_offset;
+ zret._max =
+ (high >= static_cast<int>(m_alt->m_frag_count) - 1 ? this->object_size_get() : (*m_alt->m_fragments)[high + 1].m_offset) - 1;
+ return zret;
+}
+
+/* Note - we're not handling unspecified content length and trailing segments at all here.
+ Must deal with that at some point.
+*/
+
+HTTPRangeSpec::Range
+HTTPInfo::get_uncached_hull(HTTPRangeSpec const &req, int64_t initial)
+{
+ HTTPRangeSpec::Range r;
+
+ if (m_alt && !m_alt->m_flag.complete_p) {
+ HTTPRangeSpec::Range s = req.getConvexHull();
+ if (m_alt->m_fragments) {
+ FragmentDescriptorTable &fdt = *(m_alt->m_fragments);
+ int32_t lidx;
+ int32_t ridx;
+ if (s.isValid()) {
+ lidx = this->get_frag_index_of(s._min);
+ ridx = this->get_frag_index_of(s._max);
+ } else { // not a range request, get hull of all uncached fragments
+ lidx = fdt.m_cached_idx + 1;
+ // This really isn't valid if !content_length_p, need to deal with that at some point.
+ ridx = this->get_frag_index_of(this->object_size_get());
+ }
+
+ if (lidx < 2 && !m_alt->m_earliest.m_flag.cached_p)
+ lidx = 0;
+ else {
+ if (0 == lidx)
+ ++lidx; // because if we get here with lidx == 0, earliest is cached and we should skip ahead.
+ while (lidx <= ridx && fdt[lidx].m_flag.cached_p)
+ ++lidx;
+ }
+
+ while (lidx <= ridx && fdt[ridx].m_flag.cached_p)
+ --ridx;
+
+ if (lidx <= ridx)
+ r = this->get_range_for_frags(lidx, ridx);
+ } else { // no fragments past earliest cached yet
+ r._min = m_alt->m_earliest.m_flag.cached_p ? this->get_frag_fixed_size() : 0;
+ if (s.isValid()) {
+ r._min = std::max(r._min, s._min);
+ r._max = s._max;
+ } else {
+ r._max = INT64_MAX;
+ }
+ }
+ if (r.isValid() && m_alt->m_flag.content_length_p && static_cast<int64_t>(r._max) > this->object_size_get())
+ r._max = this->object_size_get();
+ if (static_cast<int64_t>(r._min) < initial && !m_alt->m_earliest.m_flag.cached_p)
+ r._min = 0;
}
+ return r;
+}
- m_alt->m_frag_offsets[m_alt->m_frag_offset_count++] = offset;
+#if 0
+bool
+HTTPInfo::get_uncached(HTTPRangeSpec const& req, HTTPRangeSpec& result)
+{
+ bool zret = false;
+ if (m_alt && !m_alt->m_flag.complete_p) {
+ FragmentAccessor frags(m_alt);
+
+ for ( HTTPRangeSpec::const_iterator spot = req.begin(), limit = req.end() ; spot != limit ; ++spot ) {
+ int32_t lidx = this->get_frag_index_of(spot->_min);
+ int32_t ridx = this->get_frag_index_of(spot->_max);
+ while (lidx <= ridx && frags[lidx].m_flag.cached_p)
+ ++lidx;
+ if (lidx > ridx) continue; // All of this range is present.
+ while (lidx <= ridx && frags[ridx].m_flag.cached_p) // must hit missing frag at lhs at the latest
+ --ridx;
+
+ if (lidx <= ridx) {
+ result.add(this->get_range_for_frags(lidx, ridx));
+ zret = true;
+ }
+ }
+ }
+ return zret;
}
+#endif
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/hdrs/HTTP.h
----------------------------------------------------------------------
diff --git a/proxy/hdrs/HTTP.h b/proxy/hdrs/HTTP.h
index 4c80bcc..cb6b4fd 100644
--- a/proxy/hdrs/HTTP.h
+++ b/proxy/hdrs/HTTP.h
@@ -1,32 +1,33 @@
/** @file
- A brief file description
+ A brief file description
- @section license License
+ @section license License
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
#ifndef __HTTP_H__
#define __HTTP_H__
#include <assert.h>
+#include <vector>
#include "Arena.h"
-#include "INK_MD5.h"
+#include "CryptoHash.h"
#include "MIME.h"
#include "URL.h"
@@ -37,6 +38,11 @@
#define HTTP_MAJOR(v) (((v) >> 16) & 0xFFFF)
class Http2HeaderTable;
+class MIOBuffer;
+namespace ts
+{
+struct ConstBuffer;
+}
enum HTTPStatus {
HTTP_STATUS_NONE = 0,
@@ -416,6 +422,8 @@ extern int HTTP_LEN_S_MAXAGE;
extern int HTTP_LEN_NEED_REVALIDATE_ONCE;
extern int HTTP_LEN_100_CONTINUE;
+static size_t const HTTP_RANGE_BOUNDARY_LEN = 32 + 2 + 16;
+
/* Private */
void http_hdr_adjust(HTTPHdrImpl *hdrp, int32_t offset, int32_t length, int32_t delta);
@@ -463,13 +471,13 @@ int32_t http_parse_version(const char *start, const char *end);
/*
-HTTPValAccept* http_parse_accept (const char *buf, Arena *arena);
-HTTPValAcceptCharset* http_parse_accept_charset (const char *buf, Arena *arena);
-HTTPValAcceptEncoding* http_parse_accept_encoding (const char *buf, Arena *arena);
-HTTPValAcceptLanguage* http_parse_accept_language (const char *buf, Arena *arena);
-HTTPValCacheControl* http_parse_cache_control (const char *buf, Arena *arena);
-const char* http_parse_cache_directive (const char **buf);
-HTTPValRange* http_parse_range (const char *buf, Arena *arena);
+ HTTPValAccept* http_parse_accept (const char *buf, Arena *arena);
+ HTTPValAcceptCharset* http_parse_accept_charset (const char *buf, Arena *arena);
+ HTTPValAcceptEncoding* http_parse_accept_encoding (const char *buf, Arena *arena);
+ HTTPValAcceptLanguage* http_parse_accept_language (const char *buf, Arena *arena);
+ HTTPValCacheControl* http_parse_cache_control (const char *buf, Arena *arena);
+ const char* http_parse_cache_directive (const char **buf);
+ HTTPValRange* http_parse_range (const char *buf, Arena *arena);
*/
HTTPValTE *http_parse_te(const char *buf, int len, Arena *arena);
@@ -496,6 +504,235 @@ public:
int32_t m_version;
};
+/** A set of content ranges.
+
+ This represents the data for an HTTP range specification.
+ On a request this contains the request ranges. On a response it is the actual ranges in the
+ response, which are the requested ranges modified by the actual content length.
+*/
+struct HTTPRangeSpec {
+ typedef HTTPRangeSpec self;
+
+ /** A range of bytes in an object.
+
+ If @a _min > 0 and @a _max == 0 the range is backwards and counts from the
+ end of the object. That is (100,0) means the last 100 bytes of content.
+ */
+ struct Range {
+ uint64_t _min;
+ uint64_t _max;
+
+ /// Default constructor - invalid range.
+ Range() : _min(UINT64_MAX), _max(1) {}
+ /// Construct as the range ( @a low .. @a high )
+ Range(uint64_t low, uint64_t high) : _min(low), _max(high) {}
+
+ /// Test if this range is a suffix range.
+ bool isSuffix() const;
+ /// Test if this range is a valid range.
+ bool isValid() const;
+ /// Get the size (in bytes) of the range.
+ uint64_t size() const;
+ /** Convert range to absolute values for a content length of @a len.
+
+ @return @c true if the range was valid for @a len, @c false otherwise.
+ */
+ bool apply(uint64_t len);
+
+ /// Force the range to an empty state.
+ Range &invalidate();
+ };
+
+ /// Range iteration type.
+ typedef Range *iterator;
+ typedef Range const *const_iterator;
+
+ /// Current state of the overall specification.
+ /// @internal We can distinguish between @c SINGLE and @c MULTI by looking at the
+ /// size of @a _ranges but we need this to mark @c EMPTY vs. not.
+ enum State {
+ EMPTY, ///< No range.
+ INVALID, ///< Range parsing failed.
+ UNSATISFIABLE, ///< Content length application failed.
+ SINGLE, ///< Single range.
+ MULTI, ///< Multiple ranges.
+ } _state;
+
+ /// The first range value.
+ /// By separating this out we can avoid allocation in the case of a single
+ /// range value, which is by far the most common ( > 99% in my experience).
+ Range _single;
+ /// Storage for range values.
+ typedef std::vector<Range> RangeBox;
+ /// The first range is copied here if there is more than one (to simplify).
+ RangeBox _ranges;
+
+ /// Default constructor - empty range
+ HTTPRangeSpec();
+
+ /// Reset to re-usable state.
+ void clear();
+
+ /** Parse a Range field @a value and update @a this with the results.
+ @return @c true if @a value was a valid range specifier, @c false otherwise.
+ */
+ bool parseRangeFieldValue(char const *value, int len);
+
+ /** Parse a Content-Range field @a value.
+
+ @a r is set to the content range. If the content range is unsatisfied or a parse error the @a range is
+ set to be invalid.
+
+ @note The content length return is ambiguous on its own, the state of @a r must be checked.
+
+ - Multipart: @a boundary is not empty
+ - Parse error: @a CL == -1 and @a r is invalid
+ - Unsatisfiable: @a CL >= 0 and @a r is invalid
+ - Indeterminate: @c CL == -1 and @a r is valid
+
+ @return The content length, or -1 if there is an error or the content length is indeterminate.
+ */
+ static int64_t parseContentRangeFieldValue(char const *value, int len, Range &r, ts::ConstBuffer &boundary);
+
+ /// Print the range specification.
+ /// @return The number of characters printed.
+ int print(char *buff ///< Output buffer.
+ ,
+ size_t len ///< Size of output buffer.
+ ) const;
+
+ /// Print the range specification quantized.
+ /// @return The number of characters printed.
+ int print_quantized(char *buff ///< Output buffer.
+ ,
+ size_t len ///< Size of output buffer.
+ ,
+ int64_t quantum ///< Align ranges to multiples of this value.
+ ,
+ int64_t interstitial ///< Require gaps to be at least this large.
+ ) const;
+
+ /// Print the @a ranges.
+ /// @return The number of characters printed.
+ static int print_array(char *buff ///< Output buffer.
+ ,
+ size_t len ///< Size of output buffer.
+ ,
+ Range const *ranges ///< Array of ranges
+ ,
+ int count ///< # of ranges
+ );
+
+#if 0
+ /** Copy ranges from @a while applying them to the content @a length.
+
+ Ranges are copied if valid for @a length and converted to absolute offsets. The number of ranges
+ after application may be less than the @a src number of ranges. In addition ranges will be clipped
+ to @a length.
+
+ @return @c true if the range spec is satisfiable, @c false otherwise.
+ Note a range spec with no ranges is always satisfiable and that suffix ranges are also
+ always satisfiable.
+ */
+ bool apply(self const& that, uint64_t length);
+#endif
+
+ /** Update ranges to be absolute based on content @a length.
+
+ Invalid ranges are removed, ranges will be clipped as needed, and suffix ranges will be
+ converted to absolute ranges.
+
+ @return @c true if the range spec is satisfiable (there remains at least one valid range), @c false otherwise.
+ Note a range spec with no ranges is always satisfiable and that suffix ranges are also
+ always satisfiable.
+ */
+ bool apply(uint64_t length);
+
+ /** Number of distinct ranges.
+ @return Number of ranges.
+ */
+ size_t count() const;
+
+ /// Get the size (in bytes) of the ranges.
+ uint64_t size() const;
+
+ /// If this is a valid single range specification.
+ bool isSingle() const;
+
+ /// If this is a valid multi range specification.
+ bool isMulti() const;
+
+ /// Test if this contains at least one valid range.
+ bool hasRanges() const;
+
+ /// Test if this is a well formed range (may be empty).
+ bool isValid() const;
+
+ /// Test if this is a valid but empty range spec.
+ bool isEmpty() const;
+
+ /// Test if this is an unsatisfied range.
+ bool isUnsatisfied() const;
+
+ /// Access the range at index @a idx.
+ Range &operator[](int n);
+
+ /// Access the range at index @a idx.
+ Range const &operator[](int n) const;
+
+ /// Calculate the convex hull of the range spec.
+ /// The convex hull is the smallest single range that contains all of the ranges in the range spec.
+ /// @note This will return an invalid range if there are no ranges in the range spec.
+ /// @see HttpRangeSpec::Range::isValid
+ Range getConvexHull() const;
+
+ /** Calculate the content length for this range specification.
+
+ @note If a specific content length has not been @c apply 'd this will not produce
+ a usable result.
+
+ @return The content length for the ranges including the range separators.
+ */
+ uint64_t calcContentLength(uint64_t base_content_size, ///< Content size w/o ranges.
+ uint64_t ct_val_len ///< Length of Content-Type field value.
+ ) const;
+
+ /// Calculate the length of the range part boundary header.
+ static uint64_t calcPartBoundarySize(uint64_t object_size ///< Base content size
+ ,
+ uint64_t ct_val_len ///< Length of the Content-Type value (0 if none).
+ );
+
+ /** Write the range part boundary to @a out.
+ */
+ static uint64_t writePartBoundary(MIOBuffer *out ///< Output IO Buffer
+ ,
+ char const *boundary_str ///< Boundary marker string.
+ ,
+ size_t boundary_len ///< Length of boundary marker string.
+ ,
+ uint64_t total_size ///< Base content size.
+ ,
+ uint64_t low ///< Low value for the range.
+ ,
+ uint64_t high ///< High value for the raNGE.
+ ,
+ MIMEField *ctf ///< Content-Type field (@c NULL if none)
+ ,
+ bool final ///< Is this the final part boundary?
+ );
+
+ /// Iterator for first range.
+ iterator begin();
+ const_iterator begin() const;
+ /// Iterator past last range.
+ iterator end();
+ const_iterator end() const;
+
+ self &add(uint64_t low, uint64_t high);
+ self &add(Range const &r);
+};
+
class IOBufferReader;
class HTTPHdr : public MIMEHdr
@@ -631,6 +868,7 @@ public:
const char *reason_get(int *length);
void reason_set(const char *value, int length);
+ void reason_set(HTTPStatus status);
MIMEParseResult parse_req(HTTPParser *parser, const char **start, const char *end, bool eof);
MIMEParseResult parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof);
@@ -1243,6 +1481,16 @@ HTTPHdr::reason_set(const char *value, int length)
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
+inline void
+HTTPHdr::reason_set(HTTPStatus status)
+{
+ char const *phrase = http_hdr_reason_lookup(status);
+ this->reason_set(phrase, strlen(phrase));
+}
+/*-------------------------------------------------------------------------
+ -------------------------------------------------------------------------*/
+
+
inline MIMEParseResult
HTTPHdr::parse_req(HTTPParser *parser, const char **start, const char *end, bool eof)
{
@@ -1316,34 +1564,114 @@ HTTPHdr::scheme_get(int *length)
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
-enum {
- CACHE_ALT_MAGIC_ALIVE = 0xabcddeed,
- CACHE_ALT_MAGIC_MARSHALED = 0xdcbadeed,
- CACHE_ALT_MAGIC_DEAD = 0xdeadeed,
-};
+enum { CACHE_ALT_MAGIC_ALIVE = 0xabcddeed, CACHE_ALT_MAGIC_MARSHALED = 0xdcbadeed, CACHE_ALT_MAGIC_DEAD = 0xdeadeed };
-// struct HTTPCacheAlt
+/// Header for an alternate of an object.
+/// This is close to a POD, all the real API is in the @c HTTPInfo class.
+/// @note THIS IS DIRECTLY SERIALIZED TO DISK
+/// (after some tweaks, but any member in this struct will be written to disk)
struct HTTPCacheAlt {
+ /// Information about a fragment in this alternate.
+ /// @internal Currently @c Dir has only 40 bits for the disk offset of a fragment,
+ /// and since no object (or alternate) is split across stripes (and thence disks)
+ /// no fragment can have an internal offset more than 40 bits long, so 48 bits
+ /// should suffice here.
+ struct FragmentDescriptor {
+ CryptoHash m_key; ///< Key for fragment.
+ uint64_t m_offset : 48; ///< Starting offset of fragment in object.
+ union {
+ uint16_t m_flags;
+ struct {
+ unsigned int cached_p : 1; ///< Presence bit (is fragment in cache?)
+ unsigned int zero : 15; ///< Zero fill for future use.
+ } m_flag;
+ };
+ };
+
+ /** Holds the table of fragment descriptors.
+
+ @internal To avoid allocating 2 chunks of memory we hang the descriptors off the end of this structure and provide
+ a method to do the calculations. The @a m_size contains the number of descriptors, the actual byte size must be
+ computed from that. The count of valid entries is held in this structure, not in the table, because it makes
+ serialization easier. We don't serialize the explicit contents of the table struct (e.g., the capacity / @a
+ m_size value) only the descriptors.
+ */
+ struct FragmentDescriptorTable {
+ /** The number of entries in the table.
+ Because this is a 1 based array, this is also the largest valid index.
+ @note It is 1 less than the total number of fragment descriptors because earliest is stored
+ directly and not in this table.
+ */
+ uint32_t m_n;
+
+ /** Fragment index of last initial segment cached.
+
+ All fragments from the earliest to this are in cache.
+
+ @note A simple effort to minimize the cost of detecting a complete object.
+ In the normal case we'll get all the fragments in order so this will roll along nicely.
+ Otherwise we may have to do a lot of work on a single fragment, but that' still better
+ than doing it every time for every fragment.
+ */
+ uint32_t m_cached_idx;
+
+ /** Array operator for fragments in the table (1-based).
+ This is a bit tricky. The earliest fragment is special and so is @b not stored in this table.
+ To make that easier to deal with this array is one based so the containing object can simply
+ pass the index on if it's not 0 (earliest). From an external point of view the array of fragments
+ is zero based.
+ */
+ FragmentDescriptor &operator[](int idx);
+ /// Calculate the allocation size needed for a maximum array index of @a n.
+ static size_t calc_size(uint32_t n);
+ };
+
HTTPCacheAlt();
+
void copy(HTTPCacheAlt *to_copy);
- void copy_frag_offsets_from(HTTPCacheAlt *src);
void destroy();
uint32_t m_magic;
- // Writeable is set to true is we reside
- // in a buffer owned by this structure.
- // INVARIANT: if own the buffer this HttpCacheAlt
- // we also own the buffers for the request &
- // response headers
- int32_t m_writeable;
+ union {
+ uint32_t m_flags;
+ struct {
+ /** Do we own our own buffer?
+ @c true if the buffer containing this data is owned by this object.
+ INVARIANT: if we own this buffer then we also own the buffers for
+ @a m_request_hdr and @a m_response_hdr.
+ */
+ uint32_t writeable_p : 1;
+ /// Was this alternate originally stored as a partial object?
+ uint32_t composite_p : 1;
+ /// Did the origin tell us the actual length of the object?
+ uint32_t content_length_p : 1;
+ /// Are all fragments in cache?
+ uint32_t complete_p : 1;
+ /// Is the fragment table independently allocated?
+ uint32_t table_allocated_p : 1;
+ // Note - !composite_p => complete_p
+ // - complete_p => content_length_p
+ } m_flag;
+ };
+
int32_t m_unmarshal_len;
int32_t m_id;
int32_t m_rid;
- int32_t m_object_key[4];
- int32_t m_object_size[2];
+ /// # of fragments in the alternate, including the earliest fragment.
+ /// This can be zero for a resident alternate.
+ /// @internal In practice this is the high water mark for cached fragments.
+ /// Contrast with the @a m_cached_idx in the fragment table - that marks the high
+ /// water of contiguously cached fragments.
+ uint32_t m_frag_count;
+
+ /** The target size for fragments in this alternate.
+ This is @b mandatory if the object is being partially cached.
+ During read it should be used as a guideline but not considered definitive.
+ */
+ uint32_t m_fixed_fragment_size;
HTTPHdr m_request_hdr;
HTTPHdr m_response_hdr;
@@ -1351,21 +1679,23 @@ struct HTTPCacheAlt {
time_t m_request_sent_time;
time_t m_response_received_time;
- /// # of fragment offsets in this alternate.
- /// @note This is one less than the number of fragments.
- int m_frag_offset_count;
- /// Type of offset for a fragment.
- typedef uint64_t FragOffset;
- /// Table of fragment offsets.
- /// @note The offsets are forward looking so that frag[0] is the
- /// first byte past the end of fragment 0 which is also the first
- /// byte of fragment 1. For this reason there is no fragment offset
- /// for the last fragment.
- FragOffset *m_frag_offsets;
- /// # of fragment offsets built in to object.
- static int const N_INTEGRAL_FRAG_OFFSETS = 4;
- /// Integral fragment offset table.
- FragOffset m_integral_frag_offsets[N_INTEGRAL_FRAG_OFFSETS];
+ /** Special case the first (earliest, non-resident) fragment.
+ This holds the key for the earliest fragment and the object size
+ by overloading the offset in this specific instance.
+ */
+ FragmentDescriptor m_earliest;
+
+ /** Descriptors for the rest of the fragments.
+ Because of this, index 0 in this array is really the next fragment after the
+ earliest fragment. We should have the invariant
+ ( @a m_fragments != 0) == ( @a m_frag_count > 1 )
+
+ @internal I thought of using @c std::vector here, but then we end up with either
+ doing 2 allocations (one for the @c std::vector and another for its contents) or
+ writing the @c std::vector container to disk (because this struct is directly
+ serialized). Instead we do our own memory management, which doesn't make me happy either.
+ */
+ FragmentDescriptorTable *m_fragments;
// With clustering, our alt may be in cluster
// incoming channel buffer, when we are
@@ -1380,7 +1710,8 @@ struct HTTPCacheAlt {
class HTTPInfo
{
public:
- typedef HTTPCacheAlt::FragOffset FragOffset; ///< Import type.
+ typedef HTTPCacheAlt::FragmentDescriptor FragmentDescriptor; ///< Import type.
+ typedef HTTPCacheAlt::FragmentDescriptorTable FragmentDescriptorTable; ///< Import type.
HTTPCacheAlt *m_alt;
@@ -1408,7 +1739,6 @@ public:
{
m_alt = info->m_alt;
}
- void copy_frag_offsets_from(HTTPInfo *src);
HTTPInfo &operator=(const HTTPInfo &m);
inkcoreapi int marshal_length();
@@ -1439,9 +1769,9 @@ public:
m_alt->m_rid = id;
}
- INK_MD5 object_key_get();
- void object_key_get(INK_MD5 *);
- bool compare_object_key(const INK_MD5 *);
+ CryptoHash const &object_key_get();
+ void object_key_get(CryptoHash *);
+ bool compare_object_key(const CryptoHash *);
int64_t object_size_get();
void
@@ -1483,7 +1813,7 @@ public:
return m_alt->m_response_received_time;
}
- void object_key_set(INK_MD5 &md5);
+ void object_key_set(CryptoHash const &md5);
void object_size_set(int64_t size);
void
@@ -1508,14 +1838,66 @@ public:
m_alt->m_response_received_time = t;
}
+ bool
+ is_composite() const
+ {
+ return m_alt->m_flag.composite_p;
+ }
+ bool
+ is_complete() const
+ {
+ return m_alt->m_flag.complete_p;
+ }
+ bool
+ is_writeable() const
+ {
+ return m_alt->m_flag.writeable_p;
+ }
+
+ /** Compute the convex hull of uncached ranges.
+
+ If the resulting range has a minimum that is less than @a initial @b and the earliest fragment
+ is not cached then the minimum will be changed to zero. Alternatively, the initial uncached
+ segment must be at least @a initial bytes long.
+
+ @return An invalid range if all of the request is available in cache.
+ */
+ HTTPRangeSpec::Range get_uncached_hull(HTTPRangeSpec const &req ///< [in] UA request with content length applied
+ ,
+ int64_t initial ///< Minimize size for uncached initial data
+ );
+
/// Get the fragment table.
- FragOffset *get_frag_table();
- /// Get the # of fragment offsets
- /// @note This is the size of the fragment offset table, and one less
- /// than the actual # of fragments.
- int get_frag_offset_count();
- /// Add an @a offset to the end of the fragment offset table.
- void push_frag_offset(FragOffset offset);
+ /// @note There is a fragment table only for multi-fragment alternates @b and
+ /// the indexing starts with the second (non-earliest) fragment.
+ /// @deprecated - use specialized methods.
+ FragmentDescriptorTable *get_frag_table();
+
+ /// Force a descriptor at index @a idx.
+ FragmentDescriptor *force_frag_at(unsigned int idx);
+
+ /// Get the fragment index for @a offset.
+ int get_frag_index_of(int64_t offset);
+ /// Get the fragment key for an @a offset.
+ /// @note Forces fragment.
+ CryptoHash const &get_frag_key_of(int64_t offset);
+ /// Get the fragment key of the @a idx fragment.
+ /// @note Forces fragment.
+ CryptoHash const &get_frag_key(unsigned int idx);
+ /// Get the starting offset of a fragment.
+ int64_t get_frag_offset(unsigned int idx);
+
+ /// Get the number of fragments.
+ /// 0 means resident alternate, 1 means single fragment, > 1 means multi-fragment.
+ int get_frag_count() const;
+ /// Get the target fragment size.
+ uint32_t get_frag_fixed_size() const;
+ /// Mark a fragment at index @a idx as written to cache.
+ void mark_frag_write(unsigned int idx);
+ /// Check if a fragment is cached.
+ bool is_frag_cached(unsigned int idx) const;
+ /// Get the range of bytes for the fragments from @a low to @a high.
+ HTTPRangeSpec::Range get_range_for_frags(int low, int high);
// Sanity check functions
static bool check_marshalled(char *buf, int len);
@@ -1528,7 +1910,7 @@ inline void
HTTPInfo::destroy()
{
if (m_alt) {
- if (m_alt->m_writeable) {
+ if (m_alt->m_flag.writeable_p) {
m_alt->destroy();
} else if (m_alt->m_ext_buffer) {
if (m_alt->m_ext_buffer->refcount_dec() == 0) {
@@ -1545,77 +1927,307 @@ inline HTTPInfo &HTTPInfo::operator=(const HTTPInfo &m)
return *this;
}
-inline INK_MD5
+inline CryptoHash const &
HTTPInfo::object_key_get()
{
- INK_MD5 val;
- int32_t *pi = reinterpret_cast<int32_t *>(&val);
-
- pi[0] = m_alt->m_object_key[0];
- pi[1] = m_alt->m_object_key[1];
- pi[2] = m_alt->m_object_key[2];
- pi[3] = m_alt->m_object_key[3];
-
- return val;
+ return m_alt->m_earliest.m_key;
}
inline void
-HTTPInfo::object_key_get(INK_MD5 *md5)
+HTTPInfo::object_key_get(CryptoHash *key)
{
- int32_t *pi = reinterpret_cast<int32_t *>(md5);
- pi[0] = m_alt->m_object_key[0];
- pi[1] = m_alt->m_object_key[1];
- pi[2] = m_alt->m_object_key[2];
- pi[3] = m_alt->m_object_key[3];
+ memcpy(key, &(m_alt->m_earliest.m_key), sizeof(*key));
}
inline bool
-HTTPInfo::compare_object_key(const INK_MD5 *md5)
+HTTPInfo::compare_object_key(const CryptoHash *key)
{
- int32_t const *pi = reinterpret_cast<int32_t const *>(md5);
- return ((m_alt->m_object_key[0] == pi[0]) && (m_alt->m_object_key[1] == pi[1]) && (m_alt->m_object_key[2] == pi[2]) &&
- (m_alt->m_object_key[3] == pi[3]));
+ return *key == m_alt->m_earliest.m_key;
}
inline int64_t
HTTPInfo::object_size_get()
{
- int64_t val;
- int32_t *pi = reinterpret_cast<int32_t *>(&val);
-
- pi[0] = m_alt->m_object_size[0];
- pi[1] = m_alt->m_object_size[1];
- return val;
+ return m_alt->m_earliest.m_offset;
}
inline void
-HTTPInfo::object_key_set(INK_MD5 &md5)
+HTTPInfo::object_key_set(CryptoHash const &md5)
{
- int32_t *pi = reinterpret_cast<int32_t *>(&md5);
- m_alt->m_object_key[0] = pi[0];
- m_alt->m_object_key[1] = pi[1];
- m_alt->m_object_key[2] = pi[2];
- m_alt->m_object_key[3] = pi[3];
+ m_alt->m_earliest.m_key = md5;
}
inline void
HTTPInfo::object_size_set(int64_t size)
{
- int32_t *pi = reinterpret_cast<int32_t *>(&size);
- m_alt->m_object_size[0] = pi[0];
- m_alt->m_object_size[1] = pi[1];
+ m_alt->m_earliest.m_offset = size;
+ m_alt->m_flag.content_length_p = true;
+ // Invariant - if a fragment is cached, all of that fragment is cached.
+ // Therefore if the last byte is in the initial cached fragments all of the data is cached.
+ if (!m_alt->m_flag.complete_p) {
+ int64_t mco = 0; // maximum cached offset + 1
+ if (m_alt->m_fragments) {
+ if (m_alt->m_fragments->m_cached_idx >= 0)
+ mco = this->get_frag_offset(m_alt->m_fragments->m_cached_idx) + this->get_frag_fixed_size();
+ } else if (m_alt->m_earliest.m_flag.cached_p) {
+ mco = this->get_frag_fixed_size();
+ }
+ if (mco > size)
+ m_alt->m_flag.complete_p = true;
+ }
}
-inline HTTPInfo::FragOffset *
+inline HTTPInfo::FragmentDescriptorTable *
HTTPInfo::get_frag_table()
{
- return m_alt ? m_alt->m_frag_offsets : 0;
+ return m_alt ? m_alt->m_fragments : 0;
}
inline int
-HTTPInfo::get_frag_offset_count()
+HTTPInfo::get_frag_count() const
+{
+ return m_alt ? m_alt->m_frag_count : 0;
+}
+
+inline uint32_t
+HTTPInfo::get_frag_fixed_size() const
+{
+ return m_alt ? m_alt->m_fixed_fragment_size : 0;
+}
+
+inline CryptoHash const &
+HTTPInfo::get_frag_key_of(int64_t offset)
+{
+ return this->get_frag_key(this->get_frag_index_of(offset));
+}
+
+inline CryptoHash const &
+HTTPInfo::get_frag_key(unsigned int idx)
+{
+ return 0 == idx ? m_alt->m_earliest.m_key : this->force_frag_at(idx)->m_key;
+}
+
+inline int64_t
+HTTPInfo::get_frag_offset(unsigned int idx)
+{
+ return 0 == idx ? 0 : (*m_alt->m_fragments)[idx].m_offset;
+}
+
+inline bool
+HTTPInfo::is_frag_cached(unsigned int idx) const
+{
+ return m_alt && ((0 == idx && m_alt->m_earliest.m_flag.cached_p) ||
+ (m_alt->m_fragments && idx < m_alt->m_fragments->m_n && (*m_alt->m_fragments)[idx].m_flag.cached_p));
+}
+
+inline HTTPRangeSpec::HTTPRangeSpec() : _state(EMPTY)
+{
+}
+
+inline void
+HTTPRangeSpec::clear()
+{
+ _state = EMPTY;
+ RangeBox().swap(_ranges); // force memory drop.
+}
+
+inline bool
+HTTPRangeSpec::isSingle() const
+{
+ return SINGLE == _state;
+}
+
+inline bool
+HTTPRangeSpec::isMulti() const
+{
+ return MULTI == _state;
+}
+
+inline bool
+HTTPRangeSpec::isEmpty() const
+{
+ return EMPTY == _state;
+}
+
+inline bool
+HTTPRangeSpec::isUnsatisfied() const
+{
+ return UNSATISFIABLE == _state;
+}
+
+inline size_t
+HTTPRangeSpec::count() const
+{
+ return SINGLE == _state ? 1 : _ranges.size();
+}
+
+inline bool
+HTTPRangeSpec::hasRanges() const
+{
+ return SINGLE == _state || MULTI == _state;
+}
+
+inline bool
+HTTPRangeSpec::isValid() const
+{
+ return SINGLE == _state || MULTI == _state || EMPTY == _state;
+}
+
+inline HTTPRangeSpec::Range &
+HTTPRangeSpec::Range::invalidate()
+{
+ _min = UINT64_MAX;
+ _max = 1;
+ return *this;
+}
+
+inline bool
+HTTPRangeSpec::Range::isSuffix() const
+{
+ return 0 == _max && _min > 0;
+}
+
+inline bool
+HTTPRangeSpec::Range::isValid() const
+{
+ return _min <= _max || this->isSuffix();
+}
+
+inline uint64_t
+HTTPRangeSpec::Range::size() const
+{
+ return 1 + (_max - _min);
+}
+
+inline uint64_t
+HTTPRangeSpec::size() const
+{
+ uint64_t size = 0;
+ if (this->isSingle())
+ size = _single.size();
+ else if (this->isMulti()) {
+ for (RangeBox::const_iterator spot = _ranges.begin(), limit = _ranges.end(); spot != limit; ++spot)
+ size += spot->size();
+ }
+ return size;
+}
+
+inline bool
+HTTPRangeSpec::Range::apply(uint64_t len)
+{
+ ink_assert(len > 0);
+ bool zret = true; // is this range satisfiable for @a len?
+ if (this->isSuffix()) {
+ _max = len - 1;
+ _min = _min > len ? 0 : len - _min;
+ } else if (_min < len) {
+ _max = MIN(_max, len - 1);
+ } else {
+ this->invalidate();
+ zret = false;
+ }
+ return zret;
+}
+
+inline HTTPRangeSpec &
+HTTPRangeSpec::add(uint64_t low, uint64_t high)
+{
+ return this->add(Range(low, high));
+}
+
+inline HTTPRangeSpec::Range &HTTPRangeSpec::operator[](int n)
+{
+ return SINGLE == _state ? _single : _ranges[n];
+}
+
+inline HTTPRangeSpec::Range const &HTTPRangeSpec::operator[](int n) const
+{
+ return SINGLE == _state ? _single : _ranges[n];
+}
+
+inline HTTPRangeSpec::iterator
+HTTPRangeSpec::begin()
+{
+ switch (_state) {
+ case SINGLE:
+ return &_single;
+ case MULTI:
+ return &(*(_ranges.begin()));
+ default:
+ return NULL;
+ }
+}
+
+inline HTTPRangeSpec::iterator
+HTTPRangeSpec::end()
+{
+ switch (_state) {
+ case SINGLE:
+ return (&_single) + 1;
+ case MULTI:
+ return &(*(_ranges.end()));
+ default:
+ return NULL;
+ }
+}
+
+inline HTTPRangeSpec::const_iterator
+HTTPRangeSpec::begin() const
+{
+ return const_cast<self *>(this)->begin();
+}
+
+inline HTTPRangeSpec::const_iterator
+HTTPRangeSpec::end() const
+{
+ return const_cast<self *>(this)->end();
+}
+
+inline HTTPRangeSpec::Range
+HTTPRangeSpec::getConvexHull() const
+{
+ Range zret;
+ // Compute the convex hull of the original in fragment indices.
+ for (const_iterator spot = this->begin(), limit = this->end(); spot != limit; ++spot) {
+ if (spot->_min < zret._min)
+ zret._min = spot->_min;
+ if (spot->_max > zret._max)
+ zret._max = spot->_max;
+ }
+ return zret;
+}
+
+inline HTTPCacheAlt::FragmentDescriptor &HTTPCacheAlt::FragmentDescriptorTable::operator[](int idx)
+{
+ ink_assert(idx > 0);
+ return *(reinterpret_cast<FragmentDescriptor *>(reinterpret_cast<char *>(this + 1) + sizeof(FragmentDescriptor) * (idx - 1)));
+}
+
+inline size_t
+HTTPCacheAlt::FragmentDescriptorTable::calc_size(uint32_t n)
+{
+ return n < 1 ? 0 : sizeof(FragmentDescriptorTable) + n * sizeof(FragmentDescriptor);
+}
+
+#if 0
+inline
+HTTPCacheAlt::FragmentAccessor::FragmentAccessor(HTTPCacheAlt* alt)
+ : _alt(alt), _table(alt->m_fragments)
+{
+}
+
+inline HTTPCacheAlt::FragmentDescriptor&
+HTTPCacheAlt::FragmentAccessor::operator [] (int idx)
+{
+ ink_assert(idx >= 0);
+ return idx == 0 ? _alt->m_earliest : (*_table)[idx];
+}
+
+inline uint32_t
+HTTPCacheAlt::FragmentAccessor::get_initial_cached_index() const
{
- return m_alt ? m_alt->m_frag_offset_count : 0;
+ return _table ? _table->m_cached_idx : 0;
}
+#endif
#endif /* __HTTP_H__ */
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1c06db83/proxy/http/HttpCacheSM.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpCacheSM.cc b/proxy/http/HttpCacheSM.cc
index c259b38..2ba4aee 100644
--- a/proxy/http/HttpCacheSM.cc
+++ b/proxy/http/HttpCacheSM.cc
@@ -267,6 +267,37 @@ HttpCacheSM::open_read(const HttpCacheKey *key, URL *url, HTTPHdr *hdr, CacheLoo
}
}
+int
+HttpCacheSM::state_cache_open_partial_read(int evid, void *data)
+{
+ if (!open_read_cb)
+ return this->state_cache_open_read(evid, data);
+ Debug("amc", "[HttpCacheSM::state_cache_open_partial_read] second round");
+ return VC_EVENT_DONE;
+}
+
+Action *
+HttpCacheSM::open_partial_read(HTTPHdr *client_request_hdr)
+{
+ // Simple because this requires an active write VC so we know the object is there (no retries).
+ ink_assert(NULL != cache_write_vc);
+
+ // If this is a partial fill there will be a cache read VC. Resetting it to be used is challenging
+ // because it requires digging in to the internals of the VC or expanding its interface. At present
+ // it's better to just close it and re-open one that we know is valid with regard to the write VC.
+ this->close_read();
+
+ SET_HANDLER(&HttpCacheSM::state_cache_open_partial_read);
+ open_read_cb = false;
+
+ Action *action_handle = cacheProcessor.open_read(this, cache_write_vc, client_request_hdr);
+
+ if (action_handle != ACTION_RESULT_DONE)
+ pending_action = action_handle;
+
+ return open_read_cb ? ACTION_RESULT_DONE : &captive_action;
+}
+
Action *
HttpCacheSM::open_write(const HttpCacheKey *key, URL *url, HTTPHdr *request, CacheHTTPInfo *old_info, time_t pin_in_cache,
bool retry, bool allow_multiple)