blob: f7b541083b78ca41dde452a9eb95666b936d8b10 [file] [log] [blame]
The Android Open Source Project52d4c302009-03-03 19:29:09 -08001#!/usr/bin/env python
2
3#
4# Copyright 2007, The Android Open Source Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19"""
20 axl.py: HTTP Client torture tester
21
22"""
23
24import sys, time
25
26from twisted.internet import protocol, reactor, defer
27from twisted.internet.protocol import ServerFactory, Protocol
28
29import singletonmixin, log
30
31class BaseProtocol(Protocol):
32 def __init__(self):
33 self.log = log.Log.getInstance()
34
35 def write(self, data):
36 self.log("BaseProtocol.write()", len(data), data)
37 return self.transport.write(data)
38
39 def dataReceived(self, data):
40 self.log("BaseProtocol.dataReceived()", len(data), data)
41
42 def connectionMade(self):
43 self.log("BaseProtocol.connectionMade()")
44 self.transport.setTcpNoDelay(1) # send immediately
45
46 def connectionLost(self, reason):
47 self.log("BaseProtocol.connectionLost():", reason)
48
49 def sendResponse(self, response):
50 self.write("HTTP/1.1 200 OK\r\n")
51 self.write("Content-Length: %d\r\n\r\n" % len(response))
52 if len(response) > 0:
53 self.write(response)
54
55
56# Tests
57# 8000: test driven by resource request
58
59class Drop(BaseProtocol):
60 """Drops connection immediately after connect"""
61 PORT = 8001
62 def connectionMade(self):
63 BaseProtocol.connectionMade(self)
64 self.transport.loseConnection()
65
66class ReadAndDrop(BaseProtocol):
67 """Read 1st line of request, then drop connection"""
68 PORT = 8002
69 def dataReceived(self, data):
70 BaseProtocol.dataReceived(self, data)
71 self.transport.loseConnection()
72
73class GarbageStatus(BaseProtocol):
74 """Send garbage statusline"""
75 PORT = 8003
76 def dataReceived(self, data):
77 BaseProtocol.dataReceived(self, data)
78 self.write("welcome to the jungle baby\r\n")
79
80class BadHeader(BaseProtocol):
81 """Drop connection after a header is half-sent"""
82 PORT = 8004
83 def dataReceived(self, data):
84 BaseProtocol.dataReceived(self, data)
85 self.write("HTTP/1.1 200 OK\r\n")
86 self.write("Cache-Contr")
87 time.sleep(1)
88 self.transport.loseConnection()
89
90class PauseHeader(BaseProtocol):
91 """Pause for a second in middle of a header"""
92 PORT = 8005
93 def dataReceived(self, data):
94 BaseProtocol.dataReceived(self, data)
95 self.write("HTTP/1.1 200 OK\r\n")
96 self.write("Cache-Contr")
97 time.sleep(1)
98 self.write("ol: private\r\n\r\nwe've got fun and games")
99 time.sleep(1)
100 self.transport.loseConnection()
101
102class Redirect(BaseProtocol):
103 PORT = 8006
104 def dataReceived(self, data):
105 BaseProtocol.dataReceived(self, data)
106 self.write("HTTP/1.1 302 Moved Temporarily\r\n")
107 self.write("Content-Length: 0\r\n")
108 self.write("Location: http://shopping.yahoo.com/p:Canon PowerShot SD630 Digital Camera:1993588104;_ylc=X3oDMTFhZXNmcjFjBF9TAzI3MTYxNDkEc2VjA2ZwLXB1bHNlBHNsawNyc3NfcHVsc2U0LmluYw--\r\n\r\n")
109 self.transport.loseConnection()
110
111class DataDrop(BaseProtocol):
112 """Drop connection in body"""
113 PORT = 8007
114 def dataReceived(self, data):
115 if data.find("favico") >= 0:
116 self.write("HTTP/1.1 404 Not Found\r\n\r\n")
117 self.transport.loseConnection()
118 return
119
120 BaseProtocol.dataReceived(self, data)
121 self.write("HTTP/1.1 200 OK\r\n")
122# self.write("Content-Length: 100\r\n\r\n")
123 self.write("\r\n")
124# self.write("Data cuts off < 100 here!")
125# time.sleep(4)
126 self.transport.loseConnection()
127
128class DropOnce(BaseProtocol):
129 """Drop every other connection"""
130 PORT = 8008
131 COUNT = 0
132 def dataReceived(self, data):
133 BaseProtocol.dataReceived(self, data)
134 self.write("HTTP/1.1 200 OK\r\n")
135 self.write("Content-Length: 5\r\n\r\n")
136
137 if (not(DropOnce.COUNT & 1)):
138 self.write("HE")
139 else:
140 self.write("HELLO")
141 self.transport.loseConnection()
142
143 DropOnce.COUNT += 1
144
145class NoCR(BaseProtocol):
146 """Send headers without carriage returns"""
147 PORT = 8009
148 def dataReceived(self, data):
149 BaseProtocol.dataReceived(self, data)
150 self.write("HTTP/1.1 200 OK\n")
151 self.write("Content-Length: 5\n\n")
152
153 self.write("HELLO")
154 self.transport.loseConnection()
155
156class PipeDrop(BaseProtocol):
157 PORT = 8010
158 COUNT = 0
159 def dataReceived(self, data):
160 BaseProtocol.dataReceived(self, data)
161 if not PipeDrop.COUNT % 3:
162 self.write("HTTP/1.1 200 OK\n")
163 self.write("Content-Length: 943\n\n")
164
165 self.write(open("./stfu.jpg").read())
166 PipeDrop.COUNT += 1
167
168 else:
169 self.transport.loseConnection()
170 PipeDrop.COUNT += 1
171
172class RedirectLoop(BaseProtocol):
173 """Redirect back to same resource"""
174 PORT = 8011
175 def dataReceived(self, data):
176 BaseProtocol.dataReceived(self, data)
177 self.write("HTTP/1.1 302 Moved Temporarily\r\n")
178 self.write("Content-Length: 0\r\n")
179 self.write("Location: http://localhost:8011/\r\n")
180 self.write("\r\n")
181 self.transport.loseConnection()
182
183class ReadAll(BaseProtocol):
184 """Read entire request"""
185 PORT = 8012
186
187 def connectionMade(self):
188 self.count = 0
189
190 def dataReceived(self, data):
191 BaseProtocol.dataReceived(self, data)
192 self.count += len(data)
193 if self.count == 190890:
194 self.transport.loseConnection()
195
196class Timeout(BaseProtocol):
197 """Timout sending body"""
198 PORT = 8013
199
200 def connectionMade(self):
201 self.count = 0
202
203 def dataReceived(self, data):
204 BaseProtocol.dataReceived(self, data)
205 if self.count == 0: self.write("HTTP/1.1 200 OK\r\n\r\n")
206 self.count += 1
207
208class SlowResponse(BaseProtocol):
209 """Ensure client does not time out on slow writes"""
210 PORT = 8014
211
212 def connectionMade(self):
213 self.count = 0
214
215 def dataReceived(self, data):
216 BaseProtocol.dataReceived(self, data)
217 if self.count == 0: self.write("HTTP/1.1 200 OK\r\n\r\n")
218 self.sendPack(0)
219
220 def sendPack(self, count):
221 if count > 10:
222 self.transport.loseConnection()
223
224 self.write("all work and no play makes jack a dull boy %s\n" % count)
225 d = defer.Deferred()
226 d.addCallback(self.sendPack)
227 reactor.callLater(15, d.callback, count + 1)
228
229
230# HTTP/1.1 200 OK
231# Cache-Control: private
232# Content-Type: text/html
233# Set-Cookie: PREF=ID=10644de62c423aa5:TM=1155044293:LM=1155044293:S=0lHtymefQRs2j7nD; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
234# Server: GWS/2.1
235# Transfer-Encoding: chunked
236# Date: Tue, 08 Aug 2006 13:38:13 GMT
237
238def main():
239 # Initialize log
240 log.Log.getInstance(sys.stdout)
241
242 for protocol in Drop, ReadAndDrop, GarbageStatus, BadHeader, PauseHeader, \
243 Redirect, DataDrop, DropOnce, NoCR, PipeDrop, RedirectLoop, ReadAll, \
244 Timeout, SlowResponse:
245 factory = ServerFactory()
246 factory.protocol = protocol
247 reactor.listenTCP(protocol.PORT, factory)
248
249
250 reactor.run()
251
252if __name__ == '__main__':
253 main()