1
2 /* Web Polygraph http://www.web-polygraph.org/
3 * Copyright 2003-2011 The Measurement Factory
4 * Licensed under the Apache License, Version 2.0 */
5
6 #include "base/polygraph.h"
7
8 #include "base/ObjId.h"
9 #include "base/RndPermut.h"
10 #include "runtime/HttpPrinter.h"
11 #include "runtime/httpText.h"
12 #include "runtime/IOBuf.h"
13 #include "csm/ContentCfg.h"
14 #include "csm/BodyIter.h"
15
16
BodyIter()17 BodyIter::BodyIter(): theContentCfg(0), theBuf(0), theContentHash(-1) {
18 }
19
contentSize(Size aContentSize,Size aSuffixSize)20 void BodyIter::contentSize(Size aContentSize, Size aSuffixSize) {
21 theContentSize = aContentSize;
22 theSuffixSize = aSuffixSize;
23 }
24
contentSize() const25 Size BodyIter::contentSize() const {
26 if (!theSuffixSize.known()) {
27 theSuffixSize = Should(theContentCfg && theOid) ?
28 theContentCfg->calcContentSuffixSize(theOid) : Size(0);
29 }
30 // assumes response size is always known
31 if (!theContentSize.known())
32 calcContentSize();
33 return theContentSize;
34 }
35
fullEntitySize() const36 Size BodyIter::fullEntitySize() const {
37 return contentSize();
38 }
39
middleSizeLeft() const40 Size BodyIter::middleSizeLeft() const {
41 if (!ShouldUs(theContentSize.known()))
42 return theContentSize;
43
44 if (!(ShouldUs(theSuffixSize <= theContentSize)))
45 return 0;
46
47 const Size middleGoal = theContentSize - theSuffixSize;
48 if (theBuiltSize >= middleGoal)
49 return 0;
50
51 return middleGoal - theBuiltSize;
52 }
53
calcContentSize() const54 void BodyIter::calcContentSize() const {
55 Should(!theContentSize.known());
56
57 Assert(!theBuiltSize.known());
58 BodyIter *const encoder = clone();
59 WrBuf buf;
60 encoder->start(&buf);
61 while (*encoder) {
62 if (!encoder->pour())
63 Assert(false);
64 buf.reset();
65 }
66 theContentSize = encoder->builtSize();
67 encoder->putBack();
68 }
69
start(WrBuf * aBuf)70 void BodyIter::start(WrBuf *aBuf) {
71 Assert(theOid);
72 Assert(aBuf);
73 theBuf = aBuf;
74 theRng.seed(GlbPermut(theContentHash, rndBodyIter));
75 theBuiltSize = 0;
76 }
77
canPour() const78 bool BodyIter::canPour() const {
79 return theBuf && !theBuf->full() && !pouredAll();
80 }
81
pouredAll() const82 bool BodyIter::pouredAll() const {
83 return theContentSize.known() && theBuiltSize >= theContentSize;
84 }
85
86 // By default, pour() handles body prefix, middle, and suffix parts.
87 // BodyIterators that do not have those parts override this implementation.
pour()88 bool BodyIter::pour() {
89 if (theBuiltSize == 0)
90 pourPrefix();
91 if (!pourMiddle())
92 return false;
93 if (canPour() && !middleSizeLeft())
94 pourSuffix();
95 return true;
96 }
97
pourPrefix()98 void BodyIter::pourPrefix() {
99 if (Should(theContentCfg && theBuf))
100 theBuiltSize += theContentCfg->pourContentPrefix(theOid, *theBuf);
101 }
102
pourSuffix()103 void BodyIter::pourSuffix() {
104 if (Should(theContentCfg && theBuf))
105 theBuiltSize += theContentCfg->pourContentSuffix(theOid, *theBuf);
106 }
107
108 // kids must override either this method or pour() that calls this method
pourMiddle()109 bool BodyIter::pourMiddle() {
110 Assert(false);
111 return false;
112 }
113
pourRandom(const Size upToSz)114 bool BodyIter::pourRandom(const Size upToSz) {
115 const Size rndOff = IOBuf::RandomOffset(offSeed(), theBuiltSize);
116 const RndBuf &rndBuf = theContentCfg->rndBuf();
117 const Size poured = theBuf->appendRndUpTo(rndOff, upToSz, rndBuf);
118 theBuiltSize += poured;
119 return poured > 0;
120 }
121
putHeaders(HttpPrinter & hp) const122 void BodyIter::putHeaders(HttpPrinter &hp) const {
123 if (hp.putHeader(hfpContLength)) {
124 const Size clen = contentSize();
125 Assert(clen.known());
126 // Debug suffix addition via HTTP headers. TODO: Make this configurable.
127 //if (theSuffixSize.known())
128 // hp << "X-Suffix-Length: " << theSuffixSize.byte() << crlf;
129 hp << clen.byte() << crlf;
130 }
131
132 if (theContentCfg->theMimeType &&
133 hp.putHeader(hfpContType))
134 hp << theContentCfg->theMimeType << crlf;
135 if (theOid.gzipContent())
136 hp.putHeader(hfGzipContentEncoding);
137 }
138
putBack()139 void BodyIter::putBack() {
140 theContentCfg->putBodyIter(this);
141 // do not put code here
142 // body iterator must not be used after its returned to the content configuration
143 }
144