Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1906)

Unified Diff: Tools/Scripts/webkitpy/thirdparty/webpagereplay/third_party/nbhttp/spdy_common.py

Issue 18418010: Check in the thirdparty libs needed for webkitpy. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Tools/Scripts/webkitpy/thirdparty/webpagereplay/third_party/nbhttp/spdy_common.py
diff --git a/Tools/Scripts/webkitpy/thirdparty/webpagereplay/third_party/nbhttp/spdy_common.py b/Tools/Scripts/webkitpy/thirdparty/webpagereplay/third_party/nbhttp/spdy_common.py
new file mode 100644
index 0000000000000000000000000000000000000000..a978b796bad443699799983f8183fdb671da909d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/webpagereplay/third_party/nbhttp/spdy_common.py
@@ -0,0 +1,298 @@
+#!/usr/bin/env python
+import logging
+
+"""
+shared SPDY infrastructure
+
+This module contains utility functions for nbhttp and a base class
+for the SPDY-specific portions of the client and server.
+"""
+
+__author__ = "Mark Nottingham <mnot@mnot.net>"
+__copyright__ = """\
+Copyright (c) 2008-2009 Mark Nottingham
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+"""
+
+import struct
+
+compressed_hdrs = True
+try:
+ import c_zlib
+except TypeError:
+ # c_zlib loads "libz". However, that fails on Windows.
+ compressed_hdrs = False
+ import sys
+ print >>sys.stderr, (
+ 'WARNING: sdpy_common: import c_zlib failed. Using uncompressed headers.')
+
+from http_common import dummy
+
+# There is a null character ('\0') at the end of the dictionary. The '\0' might
+# be removed in future spdy versions.
+dictionary = \
+"optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-" \
+"languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi" \
+"f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser" \
+"-agent10010120020120220320420520630030130230330430530630740040140240340440" \
+"5406407408409410411412413414415416417500501502503504505accept-rangesageeta" \
+"glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic" \
+"ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran" \
+"sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati" \
+"oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo" \
+"ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe" \
+"pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic" \
+"ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1" \
+".1statusversionurl\0"
+
+# states
+WAITING, READING_FRAME_DATA = 1, 2
+
+# frame types
+DATA_FRAME = 0x00
+# Control frame, version number is 2.
+CTL_FRM = 0x8002
+CTL_SYN_STREAM = 0x01
+CTL_SYN_REPLY = 0x02
+CTL_RST_STREAM = 0x03
+CTL_SETTINGS = 0x04
+CTL_NOOP = 0x05
+CTL_PING = 0x06
+CTL_GOAWAY = 0x07
+
+# flags
+FLAG_NONE = 0x00
+FLAG_FIN = 0x01
+FLAG_UNIDIRECTIONAL = 0x02
+
+PRIORITY_MASK = 0xc0
+STREAM_MASK = 0x7fffffff
+
+class SpdyMessageHandler:
+ """
+ This is a base class for something that has to parse and/or serialise
+ SPDY messages, request or response.
+
+ For parsing, it expects you to override _input_start, _input_body and
+ _input_end, and call _handle_input when you get bytes from the network.
+
+ For serialising, it expects you to override _output.
+ """
+
+ def __init__(self):
+ self.log = lambda a:a
+ self._input_buffer = ""
+ self._input_state = WAITING
+ self._input_frame_type = None
+ self._input_flags = None
+ self._input_stream_id = None
+ self._input_frame_len = 0
+ if compressed_hdrs:
+ self._compress = c_zlib.Compressor(-1, dictionary)
+ self._decompress = c_zlib.Decompressor(dictionary)
+ else:
+ self._compress = dummy
+ self._decompress = dummy
+
+ # input-related methods
+ def _input_start(self, stream_id, hdr_tuples):
+ """
+ Take the top set of headers from a new request and queue it
+ to be processed by the application.
+ """
+ raise NotImplementedError
+
+ def _input_body(self, stream_id, chunk):
+ "Process a body chunk from the wire."
+ raise NotImplementedError
+
+ def _input_end(self, stream_id):
+ "Indicate that the response body is complete."
+ raise NotImplementedError
+
+ def _input_error(self, stream_id, err, detail=None):
+ "Indicate a parsing problem with the body."
+ raise NotImplementedError
+
+ def _handle_input(self, data):
+ """
+ Given a chunk of input, figure out what state we're in and handle it,
+ making the appropriate calls.
+ """
+ # TODO: look into reading/writing directly from the socket buffer with struct.pack_into / unpack_from.
+ if self._input_buffer != "":
+ data = self._input_buffer + data # will need to move to a list if writev comes around
+ self._input_buffer = ""
+ if self._input_state == WAITING: # waiting for a complete frame header
+ if len(data) >= 8:
+ (d1, self._input_flags, d2, d3) = struct.unpack("!IBBH", data[:8])
+ if d1 >> 31 & 0x01: # control frame
+ version = ( d1 >> 16 ) & 0x7fff # TODO: check version
+ # FIXME: we use 0x00 internally to indicate data frame
+ self._input_frame_type = d1 & 0x0000ffff
+ self._input_stream_id = None
+ else: # data frame
+ self._input_frame_type = DATA_FRAME
+ self._input_stream_id = d1 & STREAM_MASK
+ self._input_frame_len = (( d2 << 16 ) + d3)
+ self._input_state = READING_FRAME_DATA
+ self._handle_input(data[8:])
+ else:
+ self._input_buffer = data
+ elif self._input_state == READING_FRAME_DATA:
+ if len(data) >= self._input_frame_len:
+ frame_data = data[:self._input_frame_len]
+ rest = data[self._input_frame_len:]
+ if self._input_frame_type == DATA_FRAME:
+ self._input_body(self._input_stream_id, frame_data)
+ stream_id = self._input_stream_id # for FLAG_FIN below
+ elif self._input_frame_type in [CTL_SYN_STREAM, CTL_SYN_REPLY]:
+ stream_id = struct.unpack("!I", frame_data[:4])[0] & STREAM_MASK # FIXME: what if they lied about the frame len?
+ stream_priority = (struct.unpack("!b", frame_data[8:9])[0] & PRIORITY_MASK) >> 6
+ tuple_pos = 4 + 2
+ if self._input_frame_type == CTL_SYN_STREAM:
+ associated_stream_id = struct.unpack("!I", frame_data[4:8])[0]
+ tuple_pos += 4
+ hdr_tuples = self._parse_hdrs(frame_data[tuple_pos:]) or self._input_error(stream_id, 1) # FIXME: proper error here
+ # FIXME: expose pri
+ self._input_start(stream_id, stream_priority, hdr_tuples)
+ elif self._input_frame_type == CTL_RST_STREAM:
+ stream_id = struct.unpack("!I", frame_data[:4])[0] & STREAM_MASK
+ self._input_end(stream_id)
+ elif self._input_frame_type == CTL_SETTINGS:
+ pass # FIXME
+ elif self._input_frame_type == CTL_NOOP:
+ pass
+ elif self._input_frame_type == CTL_PING:
+ pass # FIXME
+ elif self._input_frame_type == CTL_GOAWAY:
+ pass # FIXME
+ else: # unknown frame type
+ raise ValueError, "Unknown frame type" # FIXME: don't puke
+ if self._input_flags & FLAG_FIN: # FIXME: invalid on CTL_RST_STREAM
+ self._input_end(stream_id)
+ self._input_state = WAITING
+ if rest:
+ self._handle_input(rest)
+ else: # don't have complete frame yet
+ self._input_buffer = data
+ else:
+ raise Exception, "Unknown input state %s" % self._input_state
+
+ def _parse_hdrs(self, data):
+ "Given a control frame data block, return a list of (name, value) tuples."
+ # TODO: separate null-delimited into separate instances
+ if self._decompress != dummy:
+ data = self._decompress(data) # FIXME: catch errors
+ cursor = 2
+ (num_hdrs,) = struct.unpack("!h", data[:cursor]) # FIXME: catch errors
+ hdrs = []
+ while cursor < len(data):
+ try:
+ (name_len,) = struct.unpack("!h", data[cursor:cursor+2]) # FIXME: catch errors
+ cursor += 2
+ name = data[cursor:cursor+name_len] # FIXME: catch errors
+ cursor += name_len
+ except IndexError:
+ raise
+ except struct.error:
+ raise
+ try:
+ (val_len,) = struct.unpack("!h", data[cursor:cursor+2]) # FIXME: catch errors
+ cursor += 2
+ value = data[cursor:cursor+val_len] # FIXME: catch errors
+ cursor += val_len
+ except IndexError:
+ raise
+ except struct.error:
+ print len(data), cursor, data # FIXME
+ raise
+ hdrs.append((name, value))
+ return hdrs
+
+ ### output-related methods
+
+ def _output(self, out):
+ raise NotImplementedError
+
+ def _handle_error(self, err):
+ raise NotImplementedError
+
+ def _ser_syn_frame(self, type, flags, stream_id, hdr_tuples):
+ "Returns a SPDY SYN_[STREAM|REPLY] frame."
+ #print "frame: " + str(self._ser_hdrs(hdr_tuples))
+ hdrs = self._ser_hdrs(hdr_tuples)
+ if self._compress != dummy:
+ hdrs = self._compress(hdrs)
+ if (type == CTL_SYN_STREAM):
+ data = struct.pack("!IIH%ds" % len(hdrs),
+ STREAM_MASK & stream_id,
+ 0x00, # associated stream id
+ 0x00, # unused
+ hdrs
+ )
+ else:
+ data = struct.pack("!IH%ds" % len(hdrs),
+ STREAM_MASK & stream_id,
+ 0x00, # unused
+ hdrs
+ )
+ return self._ser_ctl_frame(type, flags, data)
+
+ @staticmethod
+ def _ser_ctl_frame(type, flags, data):
+ "Returns a SPDY control frame."
+ # TODO: check that data len doesn't overflow
+ return struct.pack("!HHI%ds" % len(data),
+ CTL_FRM,
+ type,
+ (flags << 24) + len(data),
+ data
+ )
+
+ @staticmethod
+ def _ser_data_frame(stream_id, flags, data):
+ "Returns a SPDY data frame."
+ # TODO: check that stream_id and data len don't overflow
+ return struct.pack("!II%ds" % len(data),
+ STREAM_MASK & stream_id,
+ (flags << 24) + len(data),
+ data
+ )
+
+ @staticmethod
+ def _ser_hdrs(hdr_tuples):
+ "Returns a SPDY header block from a list of (name, value) tuples."
+ # TODO: collapse dups into null-delimited
+ hdr_tuples.sort() # required by Chromium
+ fmt = ["!H"]
+ # filter junk from hdr_tuples
+ broken = 0
+ for (n,v) in hdr_tuples:
+ if len(n) == 0 or len(v) == 0:
+ broken += 1
+ args = [len(hdr_tuples) - broken]
+ for (n,v) in hdr_tuples:
+ if len(n) == 0 or len(v) == 0:
+ continue
+ # TODO: check for overflowing n, v lengths
+ fmt.append("H%dsH%ds" % (len(n), len(v)))
+ args.extend([len(n), n, len(v), v])
+ return struct.pack("".join(fmt), *args)

Powered by Google App Engine
This is Rietveld 408576698