summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authornduca@chromium.org <nduca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-21 00:02:17 +0000
committernduca@chromium.org <nduca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-21 00:02:17 +0000
commitfc475649da19bd9b1302c23e2ac31980bcd10b6d (patch)
treef99bc1233aa3896577351b7680b17f78f8a64a0e /tools
parent6f796d60883fd0b41b296fe8a7498b7acff8c8fd (diff)
downloadchromium_src-fc475649da19bd9b1302c23e2ac31980bcd10b6d.zip
chromium_src-fc475649da19bd9b1302c23e2ac31980bcd10b6d.tar.gz
chromium_src-fc475649da19bd9b1302c23e2ac31980bcd10b6d.tar.bz2
Initial checkin for devtools-based automation
Review URL: https://chromiumcodereview.appspot.com/10825463 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@152439 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools')
-rw-r--r--tools/devtools_auto/OWNERS5
-rw-r--r--tools/devtools_auto/README4
-rw-r--r--tools/devtools_auto/third_party/websocket-client/.gitignore8
-rw-r--r--tools/devtools_auto/third_party/websocket-client/LICENSE506
-rw-r--r--tools/devtools_auto/third_party/websocket-client/MANIFEST.in2
-rw-r--r--tools/devtools_auto/third_party/websocket-client/README.chromium19
-rw-r--r--tools/devtools_auto/third_party/websocket-client/README.rst140
-rwxr-xr-xtools/devtools_auto/third_party/websocket-client/bin/wsdump.py111
-rw-r--r--tools/devtools_auto/third_party/websocket-client/data/header01.txt6
-rw-r--r--tools/devtools_auto/third_party/websocket-client/data/header02.txt6
-rw-r--r--tools/devtools_auto/third_party/websocket-client/examples/echo_client.py12
-rw-r--r--tools/devtools_auto/third_party/websocket-client/examples/echoapp_client.py41
-rw-r--r--tools/devtools_auto/third_party/websocket-client/setup.py28
-rw-r--r--tools/devtools_auto/third_party/websocket-client/test_websocket.py311
-rw-r--r--tools/devtools_auto/third_party/websocket-client/websocket.py756
15 files changed, 1955 insertions, 0 deletions
diff --git a/tools/devtools_auto/OWNERS b/tools/devtools_auto/OWNERS
new file mode 100644
index 0000000..5f68319
--- /dev/null
+++ b/tools/devtools_auto/OWNERS
@@ -0,0 +1,5 @@
+# The set noparent is temporary until src/OWNERS isn't *.
+set noparent
+nduca@chromium.org
+alokp@chromium.org
+dtu@chromium.org
diff --git a/tools/devtools_auto/README b/tools/devtools_auto/README
new file mode 100644
index 0000000..0d1d5f2
--- /dev/null
+++ b/tools/devtools_auto/README
@@ -0,0 +1,4 @@
+devtools_auto provides automation of chrome instances on top of the chrome developer tools protocol.
+
+The protocol we use:
+https://developers.google.com/chrome-developer-tools/docs/remote-debugging
diff --git a/tools/devtools_auto/third_party/websocket-client/.gitignore b/tools/devtools_auto/third_party/websocket-client/.gitignore
new file mode 100644
index 0000000..c7d73ad
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/.gitignore
@@ -0,0 +1,8 @@
+*.pyc
+*~
+*\#
+.\#*
+
+build
+dist
+websocket_client.egg-info
diff --git a/tools/devtools_auto/third_party/websocket-client/LICENSE b/tools/devtools_auto/third_party/websocket-client/LICENSE
new file mode 100644
index 0000000..c255f4a
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/LICENSE
@@ -0,0 +1,506 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
diff --git a/tools/devtools_auto/third_party/websocket-client/MANIFEST.in b/tools/devtools_auto/third_party/websocket-client/MANIFEST.in
new file mode 100644
index 0000000..9d5d250
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/MANIFEST.in
@@ -0,0 +1,2 @@
+include LICENSE
+include README.rst
diff --git a/tools/devtools_auto/third_party/websocket-client/README.chromium b/tools/devtools_auto/third_party/websocket-client/README.chromium
new file mode 100644
index 0000000..0ef7731
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/README.chromium
@@ -0,0 +1,19 @@
+Name: Python websocket-client
+Short Name: websocket-client
+URL: https://github.com/liris/websocket-client
+Version: 0
+Revision: 861f9cf354833fe3992315b60292865c5245c821
+Date: Tue Jul 10 19:57:00 2012 -0700
+License: LGPL-2.1
+License File: NOT_SHIPPED
+Security Critical: no
+
+Description:
+
+websocket-client module is WebSocket client for python. This provide the low
+level APIs for WebSocket. All APIs are the synchronous functions.
+
+Used by the python code in devtools-auto to communicate with a running Chrome instance.
+
+Local Modifications:
+None.
diff --git a/tools/devtools_auto/third_party/websocket-client/README.rst b/tools/devtools_auto/third_party/websocket-client/README.rst
new file mode 100644
index 0000000..1b7faeb
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/README.rst
@@ -0,0 +1,140 @@
+=================
+websocket-client
+=================
+
+websocket-client module is WebSocket client for python. This provide the low level APIs for WebSocket. All APIs are the synchronous functions.
+
+websocket-client supports only hybi-13.
+
+License
+============
+
+ - LGPL
+
+Installation
+=============
+
+This module is tested on only Python 2.7.
+
+Type "python setup.py install" or "pip install websocket-client" to install.
+
+This module does not depend on any other module.
+
+Example
+============
+
+Low Level API example::
+
+ from websocket import create_connection
+ ws = create_connection("ws://echo.websocket.org/")
+ print "Sending 'Hello, World'..."
+ ws.send("Hello, World")
+ print "Sent"
+ print "Reeiving..."
+ result = ws.recv()
+ print "Received '%s'" % result
+ ws.close()
+
+
+JavaScript websocket-like API example::
+
+ import websocket
+ import thread
+ import time
+
+ def on_message(ws, message):
+ print message
+
+ def on_error(ws, error):
+ print error
+
+ def on_close(ws):
+ print "### closed ###"
+
+ def on_open(ws):
+ def run(*args):
+ for i in range(3):
+ time.sleep(1)
+ ws.send("Hello %d" % i)
+ time.sleep(1)
+ ws.close()
+ print "thread terminating..."
+ thread.start_new_thread(run, ())
+
+
+ if __name__ == "__main__":
+ websocket.enableTrace(True)
+ ws = websocket.WebSocketApp("ws://echo.websocket.org/",
+ on_message = on_message,
+ on_error = on_error,
+ on_close = on_close)
+ ws.on_open = on_open
+
+ ws.run_forever()
+
+
+wsdump.py
+============
+
+wsdump.py is simple WebSocket test(debug) tool.
+
+sample for echo.websocket.org::
+
+ $ wsdump.py ws://echo.websocket.org/
+ Press Ctrl+C to quit
+ > Hello, WebSocket
+ < Hello, WebSocket
+ > How are you?
+ < How are you?
+
+Usage
+---------
+
+usage::
+ wsdump.py [-h] [-v [VERBOSE]] ws_url
+
+WebSocket Simple Dump Tool
+
+positional arguments:
+ ws_url websocket url. ex. ws://echo.websocket.org/
+
+optional arguments:
+ -h, --help show this help message and exit
+
+ -v VERBOSE, --verbose VERBOSE set verbose mode. If set to 1, show opcode. If set to 2, enable to trace websocket module
+
+example::
+
+ $ wsdump.py ws://echo.websocket.org/
+ $ wsdump.py ws://echo.websocket.org/ -v
+ $ wsdump.py ws://echo.websocket.org/ -vv
+
+ChangeLog
+============
+
+- v0.7.0
+
+ - fixed problem to read long data.(ISSUE#12)
+ - fix buffer size boundary violation
+
+- v0.6.0
+
+ - Patches: UUID4, self.keep_running, mask_key (ISSUE#11)
+ - add wsdump.py tool
+
+- v0.5.2
+
+ - fix Echo App Demo Throw Error: 'NoneType' object has no attribute 'opcode (ISSUE#10)
+
+- v0.5.1
+
+ - delete invalid print statement.
+
+- v0.5.0
+
+ - support hybi-13 protocol.
+
+- v0.4.1
+
+ - fix incorrect custom header order(ISSUE#1)
+
diff --git a/tools/devtools_auto/third_party/websocket-client/bin/wsdump.py b/tools/devtools_auto/third_party/websocket-client/bin/wsdump.py
new file mode 100755
index 0000000..02b40af
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/bin/wsdump.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+
+import argparse
+import code
+import sys
+import threading
+import websocket
+try:
+ import readline
+except:
+ pass
+
+
+OPCODE_DATA = (websocket.ABNF.OPCODE_TEXT, websocket.ABNF.OPCODE_BINARY)
+ENCODING = getattr(sys.stdin, "encoding", "").lower()
+
+class VAction(argparse.Action):
+ def __call__(self, parser, args, values, option_string=None):
+ if values==None:
+ values = "1"
+ try:
+ values = int(values)
+ except ValueError:
+ values = values.count("v")+1
+ setattr(args, self.dest, values)
+
+def parse_args():
+ parser = argparse.ArgumentParser(description="WebSocket Simple Dump Tool")
+ parser.add_argument("url", metavar="ws_url",
+ help="websocket url. ex. ws://echo.websocket.org/")
+ parser.add_argument("-v", "--verbose", default=0, nargs='?', action=VAction,
+ dest="verbose",
+ help="set verbose mode. If set to 1, show opcode. "
+ "If set to 2, enable to trace websocket module")
+
+ return parser.parse_args()
+
+
+class InteractiveConsole(code.InteractiveConsole):
+ def write(self, data):
+ sys.stdout.write("\033[2K\033[E")
+ # sys.stdout.write("\n")
+ sys.stdout.write("\033[34m" + data + "\033[39m")
+ sys.stdout.write("\n> ")
+ sys.stdout.flush()
+
+
+ def raw_input(self, prompt):
+ line = raw_input(prompt)
+ if ENCODING and ENCODING != "utf-8" and not isinstance(line, unicode):
+ line = line.decode(ENCODING).encode("utf-8")
+ elif isinstance(line, unicode):
+ line = encode("utf-8")
+
+ return line
+
+
+def main():
+ args = parse_args()
+ console = InteractiveConsole()
+ ws = websocket.create_connection(args.url)
+ if args.verbose > 1:
+ websocket.enableTrace(True)
+ print "Press Ctrl+C to quit"
+
+ def recv():
+ frame = ws.recv_frame()
+ if not frame:
+ raise websocket.WebSocketException("Not a valid frame %s" % frame)
+ elif frame.opcode in OPCODE_DATA:
+ return (frame.opcode, frame.data)
+ elif frame.opcode == websocket.ABNF.OPCODE_CLOSE:
+ ws.send_close()
+ return (frame.opcode, None)
+ elif frame.opcode == websocket.ABNF.OPCODE_PING:
+ ws.pong("Hi!")
+
+ return None, None
+
+
+ def recv_ws():
+ while True:
+ opcode, data = recv()
+ msg = None
+ if not args.verbose and opcode in OPCODE_DATA:
+ msg = "< %s" % data
+ elif args.verbose:
+ msg = "< %s: %s" % (websocket.ABNF.OPCODE_MAP.get(opcode), data)
+
+ if msg:
+ console.write(msg)
+
+ thread = threading.Thread(target=recv_ws)
+ thread.daemon = True
+ thread.start()
+
+ while True:
+ try:
+ message = console.raw_input("> ")
+ ws.send(message)
+ except KeyboardInterrupt:
+ return
+ except EOFError:
+ return
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except Exception, e:
+ print e
diff --git a/tools/devtools_auto/third_party/websocket-client/data/header01.txt b/tools/devtools_auto/third_party/websocket-client/data/header01.txt
new file mode 100644
index 0000000..3142b43
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/data/header01.txt
@@ -0,0 +1,6 @@
+HTTP/1.1 101 WebSocket Protocol Handshake
+Connection: Upgrade
+Upgrade: WebSocket
+Sec-WebSocket-Accept: Kxep+hNu9n51529fGidYu7a3wO0=
+some_header: something
+
diff --git a/tools/devtools_auto/third_party/websocket-client/data/header02.txt b/tools/devtools_auto/third_party/websocket-client/data/header02.txt
new file mode 100644
index 0000000..a9dd2ce
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/data/header02.txt
@@ -0,0 +1,6 @@
+HTTP/1.1 101 WebSocket Protocol Handshake
+Connection: Upgrade
+Upgrade WebSocket
+Sec-WebSocket-Accept: Kxep+hNu9n51529fGidYu7a3wO0=
+some_header: something
+
diff --git a/tools/devtools_auto/third_party/websocket-client/examples/echo_client.py b/tools/devtools_auto/third_party/websocket-client/examples/echo_client.py
new file mode 100644
index 0000000..1eb5f1b
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/examples/echo_client.py
@@ -0,0 +1,12 @@
+import websocket
+
+if __name__ == "__main__":
+ websocket.enableTrace(True)
+ ws = websocket.create_connection("ws://echo.websocket.org/")
+ print "Sending 'Hello, World'..."
+ ws.send("Hello, World")
+ print "Sent"
+ print "Receiving..."
+ result = ws.recv()
+ print "Received '%s'" % result
+ ws.close()
diff --git a/tools/devtools_auto/third_party/websocket-client/examples/echoapp_client.py b/tools/devtools_auto/third_party/websocket-client/examples/echoapp_client.py
new file mode 100644
index 0000000..438e4b3
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/examples/echoapp_client.py
@@ -0,0 +1,41 @@
+import websocket
+import thread
+import time
+import sys
+
+def on_message(ws, message):
+ print message
+
+def on_error(ws, error):
+ print error
+
+def on_close(ws):
+ print "### closed ###"
+
+def on_open(ws):
+ def run(*args):
+ for i in range(3):
+ # send the message, then wait
+ # so thread doesnt exit and socket
+ # isnt closed
+ ws.send("Hello %d" % i)
+ time.sleep(1)
+
+ time.sleep(1)
+ ws.close()
+ print "Thread terminating..."
+
+ thread.start_new_thread(run, ())
+
+if __name__ == "__main__":
+ websocket.enableTrace(True)
+ if len(sys.argv) < 2:
+ host = "ws://echo.websocket.org/"
+ else:
+ host = sys.argv[1]
+ ws = websocket.WebSocketApp(host,
+ on_message = on_message,
+ on_error = on_error,
+ on_close = on_close)
+ ws.on_open = on_open
+ ws.run_forever()
diff --git a/tools/devtools_auto/third_party/websocket-client/setup.py b/tools/devtools_auto/third_party/websocket-client/setup.py
new file mode 100644
index 0000000..e11400e
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/setup.py
@@ -0,0 +1,28 @@
+from setuptools import setup
+
+VERSION = "0.7.0"
+
+
+setup(
+ name="websocket-client",
+ version=VERSION,
+ description="WebSocket client for python. hybi13 is supported.",
+ long_description=open("README.rst").read(),
+ author="liris",
+ author_email="liris.pp@gmail.com",
+ license="LGPL",
+ url="https://github.com/liris/websocket-client",
+ classifiers = [
+ "Development Status :: 3 - Alpha",
+ "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
+ "Programming Language :: Python",
+ "Operating System :: MacOS :: MacOS X",
+ "Operating System :: POSIX",
+ "Operating System :: Microsoft :: Windows",
+ "Topic :: Internet",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "Intended Audience :: Developers",
+ ],
+ py_modules=["websocket"],
+ scripts=["bin/wsdump.py"]
+)
diff --git a/tools/devtools_auto/third_party/websocket-client/test_websocket.py b/tools/devtools_auto/third_party/websocket-client/test_websocket.py
new file mode 100644
index 0000000..3471f4e
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/test_websocket.py
@@ -0,0 +1,311 @@
+# -*- coding: utf-8 -*-
+#
+
+import base64
+import uuid
+import unittest
+
+# websocket-client
+import websocket as ws
+
+TRACABLE=False
+
+def create_mask_key(n):
+ return "abcd"
+
+class StringSockMock:
+ def __init__(self):
+ self.set_data("")
+ self.sent = []
+
+ def set_data(self, data):
+ self.data = data
+ self.pos = 0
+ self.len = len(data)
+
+ def recv(self, bufsize):
+ if self.len < self.pos:
+ return
+ buf = self.data[self.pos: self.pos + bufsize]
+ self.pos += bufsize
+ return buf
+
+ def send(self, data):
+ self.sent.append(data)
+
+
+class HeaderSockMock(StringSockMock):
+ def __init__(self, fname):
+ self.set_data(open(fname).read())
+ self.sent = []
+
+
+class WebSocketTest(unittest.TestCase):
+ def setUp(self):
+ ws.enableTrace(TRACABLE)
+
+ def tearDown(self):
+ pass
+
+ def testDefaultTimeout(self):
+ self.assertEquals(ws.getdefaulttimeout(), None)
+ ws.setdefaulttimeout(10)
+ self.assertEquals(ws.getdefaulttimeout(), 10)
+ ws.setdefaulttimeout(None)
+
+ def testParseUrl(self):
+ p = ws._parse_url("ws://www.example.com/r")
+ self.assertEquals(p[0], "www.example.com")
+ self.assertEquals(p[1], 80)
+ self.assertEquals(p[2], "/r")
+ self.assertEquals(p[3], False)
+
+ p = ws._parse_url("ws://www.example.com/r/")
+ self.assertEquals(p[0], "www.example.com")
+ self.assertEquals(p[1], 80)
+ self.assertEquals(p[2], "/r/")
+ self.assertEquals(p[3], False)
+
+ p = ws._parse_url("ws://www.example.com/")
+ self.assertEquals(p[0], "www.example.com")
+ self.assertEquals(p[1], 80)
+ self.assertEquals(p[2], "/")
+ self.assertEquals(p[3], False)
+
+ p = ws._parse_url("ws://www.example.com")
+ self.assertEquals(p[0], "www.example.com")
+ self.assertEquals(p[1], 80)
+ self.assertEquals(p[2], "/")
+ self.assertEquals(p[3], False)
+
+ p = ws._parse_url("ws://www.example.com:8080/r")
+ self.assertEquals(p[0], "www.example.com")
+ self.assertEquals(p[1], 8080)
+ self.assertEquals(p[2], "/r")
+ self.assertEquals(p[3], False)
+
+ p = ws._parse_url("ws://www.example.com:8080/")
+ self.assertEquals(p[0], "www.example.com")
+ self.assertEquals(p[1], 8080)
+ self.assertEquals(p[2], "/")
+ self.assertEquals(p[3], False)
+
+ p = ws._parse_url("ws://www.example.com:8080")
+ self.assertEquals(p[0], "www.example.com")
+ self.assertEquals(p[1], 8080)
+ self.assertEquals(p[2], "/")
+ self.assertEquals(p[3], False)
+
+ p = ws._parse_url("wss://www.example.com:8080/r")
+ self.assertEquals(p[0], "www.example.com")
+ self.assertEquals(p[1], 8080)
+ self.assertEquals(p[2], "/r")
+ self.assertEquals(p[3], True)
+
+ p = ws._parse_url("wss://www.example.com:8080/r?key=value")
+ self.assertEquals(p[0], "www.example.com")
+ self.assertEquals(p[1], 8080)
+ self.assertEquals(p[2], "/r?key=value")
+ self.assertEquals(p[3], True)
+
+ self.assertRaises(ValueError, ws._parse_url, "http://www.example.com/r")
+
+ def testWSKey(self):
+ key = ws._create_sec_websocket_key()
+ self.assert_(key != 24)
+ self.assert_("¥n" not in key)
+
+ def testWsUtils(self):
+ sock = ws.WebSocket()
+
+ key = "c6b8hTg4EeGb2gQMztV1/g=="
+ required_header = {
+ "upgrade": "websocket",
+ "connection": "upgrade",
+ "sec-websocket-accept": "Kxep+hNu9n51529fGidYu7a3wO0=",
+ }
+ self.assertEquals(sock._validate_header(required_header, key), True)
+
+ header = required_header.copy()
+ header["upgrade"] = "http"
+ self.assertEquals(sock._validate_header(header, key), False)
+ del header["upgrade"]
+ self.assertEquals(sock._validate_header(header, key), False)
+
+ header = required_header.copy()
+ header["connection"] = "something"
+ self.assertEquals(sock._validate_header(header, key), False)
+ del header["connection"]
+ self.assertEquals(sock._validate_header(header, key), False)
+
+
+ header = required_header.copy()
+ header["sec-websocket-accept"] = "something"
+ self.assertEquals(sock._validate_header(header, key), False)
+ del header["sec-websocket-accept"]
+ self.assertEquals(sock._validate_header(header, key), False)
+
+ def testReadHeader(self):
+ sock = ws.WebSocket()
+ sock.io_sock = sock.sock = HeaderSockMock("data/header01.txt")
+ status, header = sock._read_headers()
+ self.assertEquals(status, 101)
+ self.assertEquals(header["connection"], "upgrade")
+
+ sock.io_sock = sock.sock = HeaderSockMock("data/header02.txt")
+ self.assertRaises(ws.WebSocketException, sock._read_headers)
+
+ def testSend(self):
+ # TODO: add longer frame data
+ sock = ws.WebSocket()
+ sock.set_mask_key(create_mask_key)
+ s = sock.io_sock = sock.sock = HeaderSockMock("data/header01.txt")
+ sock.send("Hello")
+ self.assertEquals(s.sent[0], "\x81\x85abcd)\x07\x0f\x08\x0e")
+
+ sock.send("こんにちは")
+ self.assertEquals(s.sent[1], "\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")
+
+ sock.send(u"こんにちは")
+ self.assertEquals(s.sent[1], "\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")
+
+ def testRecv(self):
+ # TODO: add longer frame data
+ sock = ws.WebSocket()
+ s = sock.io_sock = sock.sock = StringSockMock()
+ s.set_data("\x81\x8fabcd\x82\xe3\xf0\x87\xe3\xf1\x80\xe5\xca\x81\xe2\xc5\x82\xe3\xcc")
+ data = sock.recv()
+ self.assertEquals(data, "こんにちは")
+
+ s.set_data("\x81\x85abcd)\x07\x0f\x08\x0e")
+ data = sock.recv()
+ self.assertEquals(data, "Hello")
+
+ def testWebSocket(self):
+ s = ws.create_connection("ws://echo.websocket.org/") #ws://localhost:8080/echo")
+ self.assertNotEquals(s, None)
+ s.send("Hello, World")
+ result = s.recv()
+ self.assertEquals(result, "Hello, World")
+
+ s.send("こにゃにゃちは、世界")
+ result = s.recv()
+ self.assertEquals(result, "こにゃにゃちは、世界")
+ s.close()
+
+ def testPingPong(self):
+ s = ws.create_connection("ws://echo.websocket.org/")
+ self.assertNotEquals(s, None)
+ s.ping("Hello")
+ s.pong("Hi")
+ s.close()
+
+ def testSecureWebSocket(self):
+ s = ws.create_connection("wss://echo.websocket.org/")
+ self.assertNotEquals(s, None)
+ self.assert_(isinstance(s.io_sock, ws._SSLSocketWrapper))
+ s.send("Hello, World")
+ result = s.recv()
+ self.assertEquals(result, "Hello, World")
+ s.send("こにゃにゃちは、世界")
+ result = s.recv()
+ self.assertEquals(result, "こにゃにゃちは、世界")
+ s.close()
+
+ def testWebSocketWihtCustomHeader(self):
+ s = ws.create_connection("ws://echo.websocket.org/",
+ headers={"User-Agent": "PythonWebsocketClient"})
+ self.assertNotEquals(s, None)
+ s.send("Hello, World")
+ result = s.recv()
+ self.assertEquals(result, "Hello, World")
+ s.close()
+
+ def testAfterClose(self):
+ from socket import error
+ s = ws.create_connection("ws://echo.websocket.org/")
+ self.assertNotEquals(s, None)
+ s.close()
+ self.assertRaises(error, s.send, "Hello")
+ self.assertRaises(error, s.recv)
+
+ def testUUID4(self):
+ """ WebSocket key should be a UUID4.
+ """
+ key = ws._create_sec_websocket_key()
+ u = uuid.UUID(bytes=base64.b64decode(key))
+ self.assertEquals(4, u.version)
+
+class WebSocketAppTest(unittest.TestCase):
+
+ class NotSetYet(object):
+ """ A marker class for signalling that a value hasn't been set yet.
+ """
+
+ def setUp(self):
+ ws.enableTrace(TRACABLE)
+
+ WebSocketAppTest.keep_running_open = WebSocketAppTest.NotSetYet()
+ WebSocketAppTest.keep_running_close = WebSocketAppTest.NotSetYet()
+ WebSocketAppTest.get_mask_key_id = WebSocketAppTest.NotSetYet()
+
+ def tearDown(self):
+
+ WebSocketAppTest.keep_running_open = WebSocketAppTest.NotSetYet()
+ WebSocketAppTest.keep_running_close = WebSocketAppTest.NotSetYet()
+ WebSocketAppTest.get_mask_key_id = WebSocketAppTest.NotSetYet()
+
+ def testKeepRunning(self):
+ """ A WebSocketApp should keep running as long as its self.keep_running
+ is not False (in the boolean context).
+ """
+
+ def on_open(self, *args, **kwargs):
+ """ Set the keep_running flag for later inspection and immediately
+ close the connection.
+ """
+ WebSocketAppTest.keep_running_open = self.keep_running
+ self.close()
+
+ def on_close(self, *args, **kwargs):
+ """ Set the keep_running flag for the test to use.
+ """
+ WebSocketAppTest.keep_running_close = self.keep_running
+
+ app = ws.WebSocketApp('ws://echo.websocket.org/', on_open=on_open, on_close=on_close)
+ app.run_forever()
+
+ self.assertFalse(isinstance(WebSocketAppTest.keep_running_open,
+ WebSocketAppTest.NotSetYet))
+
+ self.assertFalse(isinstance(WebSocketAppTest.keep_running_close,
+ WebSocketAppTest.NotSetYet))
+
+ self.assertEquals(True, WebSocketAppTest.keep_running_open)
+ self.assertEquals(False, WebSocketAppTest.keep_running_close)
+
+ def testSockMaskKey(self):
+ """ A WebSocketApp should forward the received mask_key function down
+ to the actual socket.
+ """
+
+ def my_mask_key_func():
+ pass
+
+ def on_open(self, *args, **kwargs):
+ """ Set the value so the test can use it later on and immediately
+ close the connection.
+ """
+ WebSocketAppTest.get_mask_key_id = id(self.get_mask_key)
+ self.close()
+
+ app = ws.WebSocketApp('ws://echo.websocket.org/', on_open=on_open, get_mask_key=my_mask_key_func)
+ app.run_forever()
+
+ # Note: We can't use 'is' for comparing the functions directly, need to use 'id'.
+ self.assertEquals(WebSocketAppTest.get_mask_key_id, id(my_mask_key_func))
+
+
+if __name__ == "__main__":
+ unittest.main()
+
diff --git a/tools/devtools_auto/third_party/websocket-client/websocket.py b/tools/devtools_auto/third_party/websocket-client/websocket.py
new file mode 100644
index 0000000..480bfc0
--- /dev/null
+++ b/tools/devtools_auto/third_party/websocket-client/websocket.py
@@ -0,0 +1,756 @@
+"""
+websocket - WebSocket client library for Python
+
+Copyright (C) 2010 Hiroki Ohtani(liris)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""
+
+
+import socket
+from urlparse import urlparse
+import os
+import struct
+import uuid
+import hashlib
+import base64
+import logging
+
+"""
+websocket python client.
+=========================
+
+This version support only hybi-13.
+Please see http://tools.ietf.org/html/rfc6455 for protocol.
+"""
+
+
+# websocket supported version.
+VERSION = 13
+
+# closing frame status codes.
+STATUS_NORMAL = 1000
+STATUS_GOING_AWAY = 1001
+STATUS_PROTOCOL_ERROR = 1002
+STATUS_UNSUPPORTED_DATA_TYPE = 1003
+STATUS_STATUS_NOT_AVAILABLE = 1005
+STATUS_ABNORMAL_CLOSED = 1006
+STATUS_INVALID_PAYLOAD = 1007
+STATUS_POLICY_VIOLATION = 1008
+STATUS_MESSAGE_TOO_BIG = 1009
+STATUS_INVALID_EXTENSION = 1010
+STATUS_UNEXPECTED_CONDITION = 1011
+STATUS_TLS_HANDSHAKE_ERROR = 1015
+
+logger = logging.getLogger()
+
+class WebSocketException(Exception):
+ """
+ websocket exeception class.
+ """
+ pass
+
+class WebSocketConnectionClosedException(WebSocketException):
+ """
+ If remote host closed the connection or some network error happened,
+ this exception will be raised.
+ """
+ pass
+
+default_timeout = None
+traceEnabled = False
+
+def enableTrace(tracable):
+ """
+ turn on/off the tracability.
+
+ tracable: boolean value. if set True, tracability is enabled.
+ """
+ global traceEnabled
+ traceEnabled = tracable
+ if tracable:
+ if not logger.handlers:
+ logger.addHandler(logging.StreamHandler())
+ logger.setLevel(logging.DEBUG)
+
+def setdefaulttimeout(timeout):
+ """
+ Set the global timeout setting to connect.
+
+ timeout: default socket timeout time. This value is second.
+ """
+ global default_timeout
+ default_timeout = timeout
+
+def getdefaulttimeout():
+ """
+ Return the global timeout setting(second) to connect.
+ """
+ return default_timeout
+
+def _parse_url(url):
+ """
+ parse url and the result is tuple of
+ (hostname, port, resource path and the flag of secure mode)
+
+ url: url string.
+ """
+ if ":" not in url:
+ raise ValueError("url is invalid")
+
+ scheme, url = url.split(":", 1)
+
+ parsed = urlparse(url, scheme="http")
+ if parsed.hostname:
+ hostname = parsed.hostname
+ else:
+ raise ValueError("hostname is invalid")
+ port = 0
+ if parsed.port:
+ port = parsed.port
+
+ is_secure = False
+ if scheme == "ws":
+ if not port:
+ port = 80
+ elif scheme == "wss":
+ is_secure = True
+ if not port:
+ port = 443
+ else:
+ raise ValueError("scheme %s is invalid" % scheme)
+
+ if parsed.path:
+ resource = parsed.path
+ else:
+ resource = "/"
+
+ if parsed.query:
+ resource += "?" + parsed.query
+
+ return (hostname, port, resource, is_secure)
+
+def create_connection(url, timeout=None, **options):
+ """
+ connect to url and return websocket object.
+
+ Connect to url and return the WebSocket object.
+ Passing optional timeout parameter will set the timeout on the socket.
+ If no timeout is supplied, the global default timeout setting returned by getdefauttimeout() is used.
+ You can customize using 'options'.
+ If you set "header" dict object, you can set your own custom header.
+
+ >>> conn = create_connection("ws://echo.websocket.org/",
+ ... header={"User-Agent: MyProgram",
+ ... "x-custom: header"})
+
+
+ timeout: socket timeout time. This value is integer.
+ if you set None for this value, it means "use default_timeout value"
+
+ options: current support option is only "header".
+ if you set header as dict value, the custom HTTP headers are added.
+ """
+ websock = WebSocket()
+ websock.settimeout(timeout != None and timeout or default_timeout)
+ websock.connect(url, **options)
+ return websock
+
+_MAX_INTEGER = (1 << 32) -1
+_AVAILABLE_KEY_CHARS = range(0x21, 0x2f + 1) + range(0x3a, 0x7e + 1)
+_MAX_CHAR_BYTE = (1<<8) -1
+
+# ref. Websocket gets an update, and it breaks stuff.
+# http://axod.blogspot.com/2010/06/websocket-gets-update-and-it-breaks.html
+
+def _create_sec_websocket_key():
+ uid = uuid.uuid4()
+ return base64.encodestring(uid.bytes).strip()
+
+_HEADERS_TO_CHECK = {
+ "upgrade": "websocket",
+ "connection": "upgrade",
+ }
+
+class _SSLSocketWrapper(object):
+ def __init__(self, sock):
+ self.ssl = socket.ssl(sock)
+
+ def recv(self, bufsize):
+ return self.ssl.read(bufsize)
+
+ def send(self, payload):
+ return self.ssl.write(payload)
+
+_BOOL_VALUES = (0, 1)
+def _is_bool(*values):
+ for v in values:
+ if v not in _BOOL_VALUES:
+ return False
+
+ return True
+
+class ABNF(object):
+ """
+ ABNF frame class.
+ see http://tools.ietf.org/html/rfc5234
+ and http://tools.ietf.org/html/rfc6455#section-5.2
+ """
+
+ # operation code values.
+ OPCODE_TEXT = 0x1
+ OPCODE_BINARY = 0x2
+ OPCODE_CLOSE = 0x8
+ OPCODE_PING = 0x9
+ OPCODE_PONG = 0xa
+
+ # available operation code value tuple
+ OPCODES = (OPCODE_TEXT, OPCODE_BINARY, OPCODE_CLOSE,
+ OPCODE_PING, OPCODE_PONG)
+
+ # opcode human readable string
+ OPCODE_MAP = {
+ OPCODE_TEXT: "text",
+ OPCODE_BINARY: "binary",
+ OPCODE_CLOSE: "close",
+ OPCODE_PING: "ping",
+ OPCODE_PONG: "pong"
+ }
+
+ # data length threashold.
+ LENGTH_7 = 0x7d
+ LENGTH_16 = 1 << 16
+ LENGTH_63 = 1 << 63
+
+ def __init__(self, fin = 0, rsv1 = 0, rsv2 = 0, rsv3 = 0,
+ opcode = OPCODE_TEXT, mask = 1, data = ""):
+ """
+ Constructor for ABNF.
+ please check RFC for arguments.
+ """
+ self.fin = fin
+ self.rsv1 = rsv1
+ self.rsv2 = rsv2
+ self.rsv3 = rsv3
+ self.opcode = opcode
+ self.mask = mask
+ self.data = data
+ self.get_mask_key = os.urandom
+
+ @staticmethod
+ def create_frame(data, opcode):
+ """
+ create frame to send text, binary and other data.
+
+ data: data to send. This is string value(byte array).
+ if opcode is OPCODE_TEXT and this value is uniocde,
+ data value is conveted into unicode string, automatically.
+
+ opcode: operation code. please see OPCODE_XXX.
+ """
+ if opcode == ABNF.OPCODE_TEXT and isinstance(data, unicode):
+ data = data.encode("utf-8")
+ # mask must be set if send data from client
+ return ABNF(1, 0, 0, 0, opcode, 1, data)
+
+ def format(self):
+ """
+ format this object to string(byte array) to send data to server.
+ """
+ if not _is_bool(self.fin, self.rsv1, self.rsv2, self.rsv3):
+ raise ValueError("not 0 or 1")
+ if self.opcode not in ABNF.OPCODES:
+ raise ValueError("Invalid OPCODE")
+ length = len(self.data)
+ if length >= ABNF.LENGTH_63:
+ raise ValueError("data is too long")
+
+ frame_header = chr(self.fin << 7
+ | self.rsv1 << 6 | self.rsv2 << 5 | self.rsv3 << 4
+ | self.opcode)
+ if length < ABNF.LENGTH_7:
+ frame_header += chr(self.mask << 7 | length)
+ elif length < ABNF.LENGTH_16:
+ frame_header += chr(self.mask << 7 | 0x7e)
+ frame_header += struct.pack("!H", length)
+ else:
+ frame_header += chr(self.mask << 7 | 0x7f)
+ frame_header += struct.pack("!Q", length)
+
+ if not self.mask:
+ return frame_header + self.data
+ else:
+ mask_key = self.get_mask_key(4)
+ return frame_header + self._get_masked(mask_key)
+
+ def _get_masked(self, mask_key):
+ s = ABNF.mask(mask_key, self.data)
+ return mask_key + "".join(s)
+
+ @staticmethod
+ def mask(mask_key, data):
+ """
+ mask or unmask data. Just do xor for each byte
+
+ mask_key: 4 byte string(byte).
+
+ data: data to mask/unmask.
+ """
+ _m = map(ord, mask_key)
+ _d = map(ord, data)
+ for i in range(len(_d)):
+ _d[i] ^= _m[i % 4]
+ s = map(chr, _d)
+ return "".join(s)
+
+class WebSocket(object):
+ """
+ Low level WebSocket interface.
+ This class is based on
+ The WebSocket protocol draft-hixie-thewebsocketprotocol-76
+ http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
+
+ We can connect to the websocket server and send/recieve data.
+ The following example is a echo client.
+
+ >>> import websocket
+ >>> ws = websocket.WebSocket()
+ >>> ws.connect("ws://echo.websocket.org")
+ >>> ws.send("Hello, Server")
+ >>> ws.recv()
+ 'Hello, Server'
+ >>> ws.close()
+
+ get_mask_key: a callable to produce new mask keys, see the set_mask_key
+ function's docstring for more details
+ """
+ def __init__(self, get_mask_key = None):
+ """
+ Initalize WebSocket object.
+ """
+ self.connected = False
+ self.io_sock = self.sock = socket.socket()
+ self.get_mask_key = get_mask_key
+
+ def set_mask_key(self, func):
+ """
+ set function to create musk key. You can custumize mask key generator.
+ Mainly, this is for testing purpose.
+
+ func: callable object. the fuct must 1 argument as integer.
+ The argument means length of mask key.
+ This func must be return string(byte array),
+ which length is argument specified.
+ """
+ self.get_mask_key = func
+
+ def settimeout(self, timeout):
+ """
+ Set the timeout to the websocket.
+
+ timeout: timeout time(second).
+ """
+ self.sock.settimeout(timeout)
+
+ def gettimeout(self):
+ """
+ Get the websocket timeout(second).
+ """
+ return self.sock.gettimeout()
+
+ def connect(self, url, **options):
+ """
+ Connect to url. url is websocket url scheme. ie. ws://host:port/resource
+ You can customize using 'options'.
+ If you set "header" dict object, you can set your own custom header.
+
+ >>> ws = WebSocket()
+ >>> ws.connect("ws://echo.websocket.org/",
+ ... header={"User-Agent: MyProgram",
+ ... "x-custom: header"})
+
+ timeout: socket timeout time. This value is integer.
+ if you set None for this value,
+ it means "use default_timeout value"
+
+ options: current support option is only "header".
+ if you set header as dict value,
+ the custom HTTP headers are added.
+
+ """
+ hostname, port, resource, is_secure = _parse_url(url)
+ # TODO: we need to support proxy
+ self.sock.connect((hostname, port))
+ if is_secure:
+ self.io_sock = _SSLSocketWrapper(self.sock)
+ self._handshake(hostname, port, resource, **options)
+
+ def _handshake(self, host, port, resource, **options):
+ sock = self.io_sock
+ headers = []
+ headers.append("GET %s HTTP/1.1" % resource)
+ headers.append("Upgrade: websocket")
+ headers.append("Connection: Upgrade")
+ if port == 80:
+ hostport = host
+ else:
+ hostport = "%s:%d" % (host, port)
+ headers.append("Host: %s" % hostport)
+ headers.append("Origin: %s" % hostport)
+
+ key = _create_sec_websocket_key()
+ headers.append("Sec-WebSocket-Key: %s" % key)
+ headers.append("Sec-WebSocket-Version: %s" % VERSION)
+ if "header" in options:
+ headers.extend(options["header"])
+
+ headers.append("")
+ headers.append("")
+
+ header_str = "\r\n".join(headers)
+ sock.send(header_str)
+ if traceEnabled:
+ logger.debug( "--- request header ---")
+ logger.debug( header_str)
+ logger.debug("-----------------------")
+
+ status, resp_headers = self._read_headers()
+ if status != 101:
+ self.close()
+ raise WebSocketException("Handshake Status %d" % status)
+
+ success = self._validate_header(resp_headers, key)
+ if not success:
+ self.close()
+ raise WebSocketException("Invalid WebSocket Header")
+
+ self.connected = True
+
+ def _validate_header(self, headers, key):
+ for k, v in _HEADERS_TO_CHECK.iteritems():
+ r = headers.get(k, None)
+ if not r:
+ return False
+ r = r.lower()
+ if v != r:
+ return False
+
+ result = headers.get("sec-websocket-accept", None)
+ if not result:
+ return False
+ result = result.lower()
+
+ value = key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+ hashed = base64.encodestring(hashlib.sha1(value).digest()).strip().lower()
+ return hashed == result
+
+ def _read_headers(self):
+ status = None
+ headers = {}
+ if traceEnabled:
+ logger.debug("--- response header ---")
+
+ while True:
+ line = self._recv_line()
+ if line == "\r\n":
+ break
+ line = line.strip()
+ if traceEnabled:
+ logger.debug(line)
+ if not status:
+ status_info = line.split(" ", 2)
+ status = int(status_info[1])
+ else:
+ kv = line.split(":", 1)
+ if len(kv) == 2:
+ key, value = kv
+ headers[key.lower()] = value.strip().lower()
+ else:
+ raise WebSocketException("Invalid header")
+
+ if traceEnabled:
+ logger.debug("-----------------------")
+
+ return status, headers
+
+ def send(self, payload, opcode = ABNF.OPCODE_TEXT):
+ """
+ Send the data as string.
+
+ payload: Payload must be utf-8 string or unicoce,
+ if the opcode is OPCODE_TEXT.
+ Otherwise, it must be string(byte array)
+
+ opcode: operation code to send. Please see OPCODE_XXX.
+ """
+ frame = ABNF.create_frame(payload, opcode)
+ if self.get_mask_key:
+ frame.get_mask_key = self.get_mask_key
+ data = frame.format()
+ self.io_sock.send(data)
+ if traceEnabled:
+ logger.debug("send: " + repr(data))
+
+ def ping(self, payload = ""):
+ """
+ send ping data.
+
+ payload: data payload to send server.
+ """
+ self.send(payload, ABNF.OPCODE_PING)
+
+ def pong(self, payload):
+ """
+ send pong data.
+
+ payload: data payload to send server.
+ """
+ self.send(payload, ABNF.OPCODE_PONG)
+
+ def recv(self):
+ """
+ Receive string data(byte array) from the server.
+
+ return value: string(byte array) value.
+ """
+ opcode, data = self.recv_data()
+ return data
+
+ def recv_data(self):
+ """
+ Recieve data with operation code.
+
+ return value: tuple of operation code and string(byte array) value.
+ """
+ while True:
+ frame = self.recv_frame()
+ if not frame:
+ # handle error:
+ # 'NoneType' object has no attribute 'opcode'
+ raise WebSocketException("Not a valid frame %s" % frame)
+ elif frame.opcode in (ABNF.OPCODE_TEXT, ABNF.OPCODE_BINARY):
+ return (frame.opcode, frame.data)
+ elif frame.opcode == ABNF.OPCODE_CLOSE:
+ self.send_close()
+ return (frame.opcode, None)
+ elif frame.opcode == ABNF.OPCODE_PING:
+ self.pong("Hi!")
+
+
+ def recv_frame(self):
+ """
+ recieve data as frame from server.
+
+ return value: ABNF frame object.
+ """
+ header_bytes = self._recv(2)
+ if not header_bytes:
+ return None
+ b1 = ord(header_bytes[0])
+ fin = b1 >> 7 & 1
+ rsv1 = b1 >> 6 & 1
+ rsv2 = b1 >> 5 & 1
+ rsv3 = b1 >> 4 & 1
+ opcode = b1 & 0xf
+ b2 = ord(header_bytes[1])
+ mask = b2 >> 7 & 1
+ length = b2 & 0x7f
+
+ length_data = ""
+ if length == 0x7e:
+ length_data = self._recv(2)
+ length = struct.unpack("!H", length_data)[0]
+ elif length == 0x7f:
+ length_data = self._recv(8)
+ length = struct.unpack("!Q", length_data)[0]
+
+ mask_key = ""
+ if mask:
+ mask_key = self._recv(4)
+ data = self._recv_strict(length)
+ if traceEnabled:
+ recieved = header_bytes + length_data + mask_key + data
+ logger.debug("recv: " + repr(recieved))
+
+ if mask:
+ data = ABNF.mask(mask_key, data)
+
+ frame = ABNF(fin, rsv1, rsv2, rsv3, opcode, mask, data)
+ return frame
+
+ def send_close(self, status = STATUS_NORMAL, reason = ""):
+ """
+ send close data to the server.
+
+ status: status code to send. see STATUS_XXX.
+
+ reason: the reason to close. This must be string.
+ """
+ if status < 0 or status >= ABNF.LENGTH_16:
+ raise ValueError("code is invalid range")
+ self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE)
+
+
+
+ def close(self, status = STATUS_NORMAL, reason = ""):
+ """
+ Close Websocket object
+
+ status: status code to send. see STATUS_XXX.
+
+ reason: the reason to close. This must be string.
+ """
+ if self.connected:
+ if status < 0 or status >= ABNF.LENGTH_16:
+ raise ValueError("code is invalid range")
+
+ try:
+ self.send(struct.pack('!H', status) + reason, ABNF.OPCODE_CLOSE)
+ timeout = self.sock.gettimeout()
+ self.sock.settimeout(3)
+ try:
+ frame = self.recv_frame()
+ if logger.isEnabledFor(logging.DEBUG):
+ logger.error("close status: " + repr(frame.data))
+ except:
+ pass
+ self.sock.settimeout(timeout)
+ self.sock.shutdown(socket.SHUT_RDWR)
+ except:
+ pass
+ self._closeInternal()
+
+ def _closeInternal(self):
+ self.connected = False
+ self.sock.close()
+ self.io_sock = self.sock
+
+ def _recv(self, bufsize):
+ bytes = self.io_sock.recv(bufsize)
+ if bytes == 0:
+ raise WebSocketConnectionClosedException()
+ return bytes
+
+ def _recv_strict(self, bufsize):
+ remaining = bufsize
+ bytes = ""
+ while remaining:
+ bytes += self._recv(remaining)
+ remaining = bufsize - len(bytes)
+
+ return bytes
+
+ def _recv_line(self):
+ line = []
+ while True:
+ c = self._recv(1)
+ line.append(c)
+ if c == "\n":
+ break
+ return "".join(line)
+
+class WebSocketApp(object):
+ """
+ Higher level of APIs are provided.
+ The interface is like JavaScript WebSocket object.
+ """
+ def __init__(self, url,
+ on_open = None, on_message = None, on_error = None,
+ on_close = None, keep_running = True, get_mask_key = None):
+ """
+ url: websocket url.
+ on_open: callable object which is called at opening websocket.
+ this function has one argument. The arugment is this class object.
+ on_message: callbale object which is called when recieved data.
+ on_message has 2 arguments.
+ The 1st arugment is this class object.
+ The passing 2nd arugment is utf-8 string which we get from the server.
+ on_error: callable object which is called when we get error.
+ on_error has 2 arguments.
+ The 1st arugment is this class object.
+ The passing 2nd arugment is exception object.
+ on_close: callable object which is called when closed the connection.
+ this function has one argument. The arugment is this class object.
+ keep_running: a boolean flag indicating whether the app's main loop should
+ keep running, defaults to True
+ get_mask_key: a callable to produce new mask keys, see the WebSocket.set_mask_key's
+ docstring for more information
+ """
+ self.url = url
+ self.on_open = on_open
+ self.on_message = on_message
+ self.on_error = on_error
+ self.on_close = on_close
+ self.keep_running = keep_running
+ self.get_mask_key = get_mask_key
+ self.sock = None
+
+ def send(self, data):
+ """
+ send message. data must be utf-8 string or unicode.
+ """
+ if self.sock.send(data) == 0:
+ raise WebSocketConnectionClosedException()
+
+ def close(self):
+ """
+ close websocket connection.
+ """
+ self.keep_running = False
+ self.sock.close()
+
+ def run_forever(self):
+ """
+ run event loop for WebSocket framework.
+ This loop is infinite loop and is alive during websocket is available.
+ """
+ if self.sock:
+ raise WebSocketException("socket is already opened")
+ try:
+ self.sock = WebSocket(self.get_mask_key)
+ self.sock.connect(self.url)
+ self._run_with_no_err(self.on_open)
+ while self.keep_running:
+ data = self.sock.recv()
+ if data is None:
+ break
+ self._run_with_no_err(self.on_message, data)
+ except Exception, e:
+ self._run_with_no_err(self.on_error, e)
+ finally:
+ self.sock.close()
+ self._run_with_no_err(self.on_close)
+ self.sock = None
+
+ def _run_with_no_err(self, callback, *args):
+ if callback:
+ try:
+ callback(self, *args)
+ except Exception, e:
+ if logger.isEnabledFor(logging.DEBUG):
+ logger.error(e)
+
+
+if __name__ == "__main__":
+ enableTrace(True)
+ ws = create_connection("ws://echo.websocket.org/")
+ print "Sending 'Hello, World'..."
+ ws.send("Hello, World")
+ print "Sent"
+ print "Receiving..."
+ result = ws.recv()
+ print "Received '%s'" % result
+ ws.close()