0&&(c=b[x](e),b=b[x](0,e)),f<0?b+"?"+d+c:b+"&"+d+c)};var bd="|",dd=function(a,b,c,d,e,f,j,p,n){var q=cd(a,b);q||(q={},a.get(ab)[k](q));q.id_=b;q.affiliation_=c;q.total_=d;q.tax_=e;q.shipping_=f;q.city_=j;q.state_=p;q.country_=n;q.items_=[];return q},ed=function(a,b,c,d,e,f,j){var a=cd(a,b)||dd(a,b,"",0,0,0,"","",""),p;a:{if(a&&a.items_){p=a.items_;for(var n=0;n=a.b(Xb,0))return!1;var c=hd();c==g&&(c=id());if(c==g||c==Infinity||isNaN(c))return!1;c>0?b(jd(c)):pa(U,"load",function(){ld(a,b)},!1);return!0},jd=function(a){var b=new Gc,c=i.min(i.floor(a/100),5E3);b.e(14,1,c>0?c+"00":"0");b.j(14,1,a);return b},hd=function(){var a=U.performance||U.webkitPerformance;return(a=a&&a.timing)&&a.loadEventStart-a.fetchStart},id=function(){if(U.top==U){var a=U.external,b=a&&a.onloadT;a&&!a.isValidLoadTime&&(b=g);b>2147483648&&(b=g);
-b>0&&a.setPageReadyTime();return b}};var Q=function(a,b,c){function d(a){return function(b){if((b=b.get(Zb)[a])&&b[r])for(var c=ac(e,a),d=0;d-1?(D(13),this.set(db,a,!0)):typeof a==="object"&&a!==h&&this.oa(a);this.a.f("page")};A.t=function(a,b,c,d){if(a==""||!Ec(a)||b==""||!Ec(b))return!1;if(c!=g&&!Ec(c))return!1;if(d!=g&&!Fc(d))return!1;this.set(Ob,a,!0);this.set(Pb,b,!0);this.set(Qb,c,!0);this.set(Tb,d,!0);this.a.f("event");return!0};
-A.la=function(a,b,c,d){if(!a||!b)return!1;this.set(Ub,a[x](0,15),!0);this.set(Vb,b[x](0,15),!0);this.set(Wb,c||F[v].href,!0);d&&this.set(db,d,!0);this.a.f("social");return!0};A.ja=function(){var a=this;return ld(this.a,function(b){a.s(b)})};A.ma=function(){this.a.f("trans")};A.s=function(a){this.set(cb,a,!0);this.a.f("event")};A.S=function(a){this.l();var b=this;return{_trackEvent:function(c,d,e){D(91);b.t(a,c,d,e)}}};A.V=function(a){return this.get(a)};
-A.da=function(a,b){if(a)if(a!=g&&(a.constructor+"")[m]("String")>-1)this.set(a,b);else if(typeof a=="object")for(var c in a)a.hasOwnProperty(c)&&this.set(c,a[c])};A.addEventListener=function(a,b){var c=this.get(Zb)[a];c&&c[k](b)};A.removeEventListener=function(a,b){for(var c=this.get(Zb)[a],d=0;c&&de.get(Xa))a=!1;else if(!b||!c||C(b)[r]+C(c)[r]>64)a=!1;else{d!=1&&d!=2&&(d=3);var f={};ca(f,b);f.value=c;f.scope=d;e.get(M)[a]=f;a=!0}a&&this.a.i();return a};A.U=function(a){this.a.get(M)[a]=g;this.a.i()};A.Y=function(a){return(a=this.a.get(M)[a])&&a[ia]==1?a[ea]:g};A.ha=function(a,b,c){this.g().e(a,b,c)};A.ia=function(a,b,c){this.g().j(a,b,c)};A.Z=function(a,b){return this.g().w(a,b)};
-A.$=function(a,b){return this.g().z(a,b)};A.P=function(a){this.g().u(a)};A.Q=function(a){this.g().v(a)};A.T=function(){return new Gc};A.H=function(a){a&&this.get(Za)[k](a[z]())};A.M=function(){this.set(Za,[])};A.I=function(a){a&&this.get($a)[k](a[z]())};A.N=function(){this.set($a,[])};A.K=function(a,b,c){if(a&&b){var d=this.get(Ya);d.splice(c?0:d[r],0,a+":"+b[z]())}};A.O=function(){this.set(Ya,[])};
-A.R=function(a){this.a[da]();var b=this.get(L),c=ra(V("__utmx"))||"";this.set(L,a);this.a.i();Nc(this.a,"__utmx",c);this.set(L,b)};A.l=function(){this.a[da]()};A.ga=function(a){a&&a!=""&&(this.set(ob,a),this.a.f("var"))};var md=function(a){a.get(Mb)!=="trans"&&a.b(yb,0)>=500&&a[u]();if(a.get(Mb)==="event"){var b=(new Date).getTime(),c=a.b(zb,0),d=a.b(ub,0),c=i.floor(0.2*((b-(c!=d?c:c*1E3))/1E3));c>0&&(a.set(zb,b),a.set(O,i.min(10,a.b(O,0)+c)));a.b(O,0)<=0&&a[u]()}},od=function(a){a.get(Mb)==="event"&&a.set(O,i.max(0,a.b(O,10)-1))};var pd=function(){var a=[];this.add=function(b,c,d){d&&(c=C(""+c));a[k](b+"="+c)};this.toString=function(){return a[y]("&")}},qd=function(a,b){(b||a.get(Wa)!=2)&&a.m(yb)},rd=function(a,b){b.add("utmwv","5.1.2");b.add("utms",a.get(yb));b.add("utmn",na());var c=F[v].hostname;B(c)||b.add("utmhn",c,!0);c=a.get(Ua);c!=100&&b.add("utmsp",c,!0)},td=function(a,b){b.add("utmac",a.get(za));sd(a,b);Z.o&&b.add("aip",1);b.add("utmu",wc.va())},sd=function(a,b){function c(a,b){b&&d[k](a+"="+b+";")}var d=[];c("__utma",
-ic(a));c("__utmz",oc(a,!1));c("__utmv",lc(a,!0));c("__utmx",ra(V("__utmx")));b.add("utmcc",d[y]("+"),!0)},ud=function(a,b){a.get(Ia)&&(b.add("utmcs",a.get(mb),!0),b.add("utmsr",a.get(hb)),b.add("utmsc",a.get(ib)),b.add("utmul",a.get(lb)),b.add("utmje",a.get(jb)),b.add("utmfl",a.get(kb),!0))},vd=function(a,b){a.get(La)&&a.get(eb)&&b.add("utmdt",a.get(eb),!0);b.add("utmhid",a.get(gb));b.add("utmr",xa(a.get(fb),a.get(L)),!0);b.add("utmp",C(a.get(db),!0),!0)},wd=function(a,b){for(var c=a.get(bb),d=a.get(cb),
-e=a.get(M)||[],f=0;f=0&&![].reduce)throw new Dd(a[r]);Fd(a,b)||Gd(a,b)}else throw new Cd(a[r]);},Ed=function(a,b,c){var c=c||Bd+"/__utm.gif?",d=new Image(1,1);d.src=c+a;d.onload=function(){d.onload=
-h;b()}},Fd=function(a,b){var c,d=Bd+"/p/__utm.gif",e=U.XDomainRequest;if(e)c=new e,c.open("POST",d);else if(e=U.XMLHttpRequest)e=new e,"withCredentials"in e&&(c=e,c.open("POST",d,!0),c.setRequestHeader("Content-Type","text/plain"));if(c)return c.onreadystatechange=function(){c.readyState==4&&(b(),c=h)},c.send(a),!0},Gd=function(a,b){if(F.body){a=aa(a);try{var c=F.createElement('')}catch(d){c=F.createElement("iframe"),ca(c,a)}c.height="0";c.width="0";c.style.display="none";
-c.style.visibility="hidden";var e=F[v],e=Bd+"/u/post_iframe.html#"+aa(e.protocol+"//"+e[ha]+"/favicon.ico"),f=function(){c.src="";c.parentNode&&c.parentNode.removeChild(c)};pa(U,"beforeunload",f);var j=!1,p=0,n=function(){if(!j){try{if(p>9||c.contentWindow[v][ha]==F[v][ha]){j=!0;f();qa(U,"beforeunload",f);b();return}}catch(a){}p++;setTimeout(n,200)}};pa(c,"load",n);F.body.appendChild(c);c.src=e}else xc(function(){Gd(a,b)},100)};var $=function(){this.o=!1;this.A={};this.ra=0;this._gasoCPath=this._gasoDomain=g;P($[s],"_createTracker",$[s].k,55);P($[s],"_getTracker",$[s].ta,0);P($[s],"_getTrackerByName",$[s].p,51);P($[s],"_anonymizeIp",$[s].sa,16);$b()};$[s].ta=function(a,b){return this.k(a,g,b)};$[s].k=function(a,b,c){b&&D(23);c&&D(67);b==g&&(b="~"+Z.ra++);return Z.A[b]=new Q(b,a,c)};$[s].p=function(a){a=a||"";return Z.A[a]||Z.k(g,a)};$[s].sa=function(){this.o=!0};var Hd=function(a){if(F.webkitVisibilityState=="prerender")return!1;a();return!0};var Z=new $;var Id=U._gat;Id&&typeof Id._getTracker=="function"?Z=Id:U._gat=Z;var Dc=new Y;(function(a){if(!Hd(a)){D(123);var b=!1,c=function(){!b&&Hd(a)&&(D(124),b=!0,qa(F,"webkitvisibilitychange",c))};pa(F,"webkitvisibilitychange",c)}})(function(){var a=U._gaq,b=!1;if(a&&typeof a[k]=="function"&&(b=Object[s][o].call(Object(a))=="[object Array]",!b)){Dc=a;return}U._gaq=Dc;b&&Dc[k].apply(Dc,a)});})();
diff --git a/eBook/examples/chapter_15/Codelab Writing Web Applications - The Go Programming Language_files/godocs.js b/eBook/examples/chapter_15/Codelab Writing Web Applications - The Go Programming Language_files/godocs.js
deleted file mode 100644
index 946c4c3..0000000
--- a/eBook/examples/chapter_15/Codelab Writing Web Applications - The Go Programming Language_files/godocs.js
+++ /dev/null
@@ -1,190 +0,0 @@
-// Except as noted, this content is licensed under Creative Commons
-// Attribution 3.0
-
-/* A little code to ease navigation of these documents.
- *
- * On window load we:
- * + Generate a table of contents (godocs_generateTOC)
- * + Add links up to the top of the doc from each section (godocs_addTopLinks)
- */
-
-/* We want to do some stuff on page load (after the HTML is rendered).
- So listen for that:
- */
-function bindEvent(el, e, fn) {
- if (el.addEventListener){
- el.addEventListener(e, fn, false);
- } else if (el.attachEvent){
- el.attachEvent('on'+e, fn);
- }
-}
-bindEvent(window, 'load', godocs_onload);
-
-function godocs_onload() {
- godocs_bindSearchEvents();
- godocs_generateTOC();
- godocs_addTopLinks();
-}
-
-function godocs_bindSearchEvents() {
- var search = document.getElementById('search');
- if (!search) {
- // no search box (index disabled)
- return;
- }
- function clearInactive() {
- if (search.className == "inactive") {
- search.value = "";
- search.className = "";
- }
- }
- function restoreInactive() {
- if (search.value != "") {
- return;
- }
- if (search.type != "search") {
- search.value = search.getAttribute("placeholder");
- }
- search.className = "inactive";
- }
- restoreInactive();
- bindEvent(search, 'focus', clearInactive);
- bindEvent(search, 'blur', restoreInactive);
-}
-
-/* Generates a table of contents: looks for h2 and h3 elements and generates
- * links. "Decorates" the element with id=="nav" with this table of contents.
- */
-function godocs_generateTOC() {
- var navbar = document.getElementById('nav');
- if (!navbar) { return; }
-
- var toc_items = [];
-
- var i;
- for (i = 0; i < navbar.parentNode.childNodes.length; i++) {
- var node = navbar.parentNode.childNodes[i];
- if ((node.tagName == 'h2') || (node.tagName == 'H2')) {
- if (!node.id) {
- node.id = 'tmp_' + i;
- }
- var text = godocs_nodeToText(node);
- if (!text) { continue; }
-
- var textNode = document.createTextNode(text);
-
- var link = document.createElement('a');
- link.href = '#' + node.id;
- link.appendChild(textNode);
-
- // Then create the item itself
- var item = document.createElement('dt');
-
- item.appendChild(link);
- toc_items.push(item);
- }
- if ((node.tagName == 'h3') || (node.tagName == 'H3')) {
- if (!node.id) {
- node.id = 'tmp_' + i;
- }
- var text = godocs_nodeToText(node);
- if (!text) { continue; }
-
- var textNode = document.createTextNode(text);
-
- var link = document.createElement('a');
- link.href = '#' + node.id;
- link.appendChild(textNode);
-
- // Then create the item itself
- var item = document.createElement('dd');
-
- item.appendChild(link);
- toc_items.push(item);
- }
- }
-
- if (toc_items.length <= 1) { return; }
-
- var dl1 = document.createElement('dl');
- var dl2 = document.createElement('dl');
-
- var split_index = (toc_items.length / 2) + 1;
- if (split_index < 8) {
- split_index = toc_items.length;
- }
-
- for (i = 0; i < split_index; i++) {
- dl1.appendChild(toc_items[i]);
- }
- for (/* keep using i */; i < toc_items.length; i++) {
- dl2.appendChild(toc_items[i]);
- }
-
- var tocTable = document.createElement('table');
- navbar.appendChild(tocTable);
- tocTable.className = 'unruled';
- var tocBody = document.createElement('tbody');
- tocTable.appendChild(tocBody);
-
- var tocRow = document.createElement('tr');
- tocBody.appendChild(tocRow);
-
- // 1st column
- var tocCell = document.createElement('td');
- tocCell.className = 'first';
- tocRow.appendChild(tocCell);
- tocCell.appendChild(dl1);
-
- // 2nd column
- tocCell = document.createElement('td');
- tocRow.appendChild(tocCell);
- tocCell.appendChild(dl2);
-}
-
-/* Returns the "This sweet header" from This sweet header
.
- * Takes a node, returns a string.
- */
-function godocs_nodeToText(node) {
- var TEXT_NODE = 3; // Defined in Mozilla but not MSIE :(
-
- var text = '';
- for (var j = 0; j != node.childNodes.length; j++) {
- var child = node.childNodes[j];
- if (child.nodeType == TEXT_NODE) {
- if (child.nodeValue != '[Top]') { //ok, that's a hack, but it works.
- text = text + child.nodeValue;
- }
- } else {
- text = text + godocs_nodeToText(child);
- }
- }
- return text;
-}
-
-/* For each H2 heading, add a link up to the #top of the document.
- * (As part of this: ensure existence of 'top' named anchor link
- * (theoretically at doc's top).)
- */
-function godocs_addTopLinks() {
- /* Make sure there's a "top" to link to. */
- var top = document.getElementById('top');
- if (!top) {
- document.body.id = 'top';
- }
-
- if (!document.getElementsByTagName) return; // no browser support
-
- var headers = document.getElementsByTagName('h2');
-
- for (var i = 0; i < headers.length; i++) {
- var span = document.createElement('span');
- span.className = 'navtop';
- var link = document.createElement('a');
- span.appendChild(link);
- link.href = '#top';
- var textNode = document.createTextNode('[Top]');
- link.appendChild(textNode);
- headers[i].appendChild(span);
- }
-}
diff --git a/eBook/examples/chapter_15/client.go b/eBook/examples/chapter_15/client.go
deleted file mode 100644
index 9c6d861..0000000
--- a/eBook/examples/chapter_15/client.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "net"
- "bufio"
- "strings"
-)
-
-func main() {
- conn, err := net.Dial("tcp", "localhost:50000")
- if err != nil {
- // No connection could be made because the target machine actively refused it.
- fmt.Println("Error dialing", err.Error())
- return // terminate program
- }
-
- inputReader := bufio.NewReader(os.Stdin)
- fmt.Println("First, what is your name?")
- clientName, _ := inputReader.ReadString('\n')
- // fmt.Printf("CLIENTNAME %s",clientName)
- trimmedClient := strings.Trim(clientName, "\r\n") // "\r\n" on Windows, "\n" on Linux
-
- for {
- fmt.Println("What to send to the server? Type Q to quit.")
- input, _ := inputReader.ReadString('\n')
- trimmedInput := strings.Trim(input, "\r\n")
- // fmt.Printf("input:--%s--",input)
- // fmt.Printf("trimmedInput:--%s--",trimmedInput)
- if trimmedInput == "Q" {
- return
- }
- _, err = conn.Write([]byte(trimmedClient + " says: " + trimmedInput))
- }
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/00changelog.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/00changelog.i
deleted file mode 100644
index d3a8311..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/00changelog.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/branch b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/branch
deleted file mode 100644
index 4ad96d5..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/branch
+++ /dev/null
@@ -1 +0,0 @@
-default
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/cache/branchheads b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/cache/branchheads
deleted file mode 100644
index 2844416..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/cache/branchheads
+++ /dev/null
@@ -1,2 +0,0 @@
-844fb91a777b63798d4657e1c40669e8968f79ad 4
-844fb91a777b63798d4657e1c40669e8968f79ad default
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/cache/tags b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/cache/tags
deleted file mode 100644
index 25f9984..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/cache/tags
+++ /dev/null
@@ -1,2 +0,0 @@
-4 844fb91a777b63798d4657e1c40669e8968f79ad
-
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/dirstate b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/dirstate
deleted file mode 100644
index 3f0d5e6..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/dirstate and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/hgrc b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/hgrc
deleted file mode 100644
index 692ebb4..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/hgrc
+++ /dev/null
@@ -1,2 +0,0 @@
-[paths]
-default = https://code.google.com/p/go.net
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/requires b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/requires
deleted file mode 100644
index ca69271..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/requires
+++ /dev/null
@@ -1,4 +0,0 @@
-revlogv1
-store
-fncache
-dotencode
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/00changelog.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/00changelog.i
deleted file mode 100644
index aa4cdf8..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/00changelog.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/00manifest.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/00manifest.i
deleted file mode 100644
index 9fb8a62..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/00manifest.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_a_u_t_h_o_r_s.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_a_u_t_h_o_r_s.i
deleted file mode 100644
index c16b17e..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_a_u_t_h_o_r_s.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_c_o_n_t_r_i_b_u_t_o_r_s.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_c_o_n_t_r_i_b_u_t_o_r_s.i
deleted file mode 100644
index b853cf0..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_c_o_n_t_r_i_b_u_t_o_r_s.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_l_i_c_e_n_s_e.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_l_i_c_e_n_s_e.i
deleted file mode 100644
index aa52959..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_l_i_c_e_n_s_e.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_r_e_a_d_m_e.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_r_e_a_d_m_e.i
deleted file mode 100644
index 75b7cc9..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/_r_e_a_d_m_e.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/codereview.cfg.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/codereview.cfg.i
deleted file mode 100644
index 833f42f..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/codereview.cfg.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/dict/dict.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/dict/dict.go.i
deleted file mode 100644
index 402e254..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/dict/dict.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/read.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/read.go.i
deleted file mode 100644
index 8f166d4..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/read.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/spdy__test.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/spdy__test.go.i
deleted file mode 100644
index cfd8899..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/spdy__test.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/types.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/types.go.i
deleted file mode 100644
index 35054ee..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/types.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/write.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/write.go.i
deleted file mode 100644
index c81b7d5..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/spdy/write.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/client.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/client.go.i
deleted file mode 100644
index 65d4320..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/client.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hixie.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hixie.go.i
deleted file mode 100644
index d52174f..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hixie.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hixie__test.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hixie__test.go.i
deleted file mode 100644
index baf9710..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hixie__test.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hybi.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hybi.go.i
deleted file mode 100644
index 83339c2..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hybi.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hybi__test.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hybi__test.go.i
deleted file mode 100644
index 5cdb6cf..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/hybi__test.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/server.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/server.go.i
deleted file mode 100644
index 702fc38..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/server.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/websocket.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/websocket.go.i
deleted file mode 100644
index 3e421a6..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/websocket.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/websocket__test.go.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/websocket__test.go.i
deleted file mode 100644
index 03bae85..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/websocket/websocket__test.go.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/~2ehgignore.i b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/~2ehgignore.i
deleted file mode 100644
index 3654614..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/data/~2ehgignore.i and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/fncache b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/fncache
deleted file mode 100644
index a0058a5..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/fncache
+++ /dev/null
@@ -1,19 +0,0 @@
-data/websocket/hybi.go.i
-data/AUTHORS.i
-data/CONTRIBUTORS.i
-data/spdy/read.go.i
-data/dict/dict.go.i
-data/codereview.cfg.i
-data/README.i
-data/websocket/websocket_test.go.i
-data/.hgignore.i
-data/websocket/hixie.go.i
-data/websocket/hixie_test.go.i
-data/websocket/websocket.go.i
-data/LICENSE.i
-data/spdy/types.go.i
-data/spdy/spdy_test.go.i
-data/websocket/client.go.i
-data/spdy/write.go.i
-data/websocket/hybi_test.go.i
-data/websocket/server.go.i
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/undo b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/undo
deleted file mode 100644
index 93c2690..0000000
Binary files a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/store/undo and /dev/null differ
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/undo.bookmarks b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/undo.bookmarks
deleted file mode 100644
index e69de29..0000000
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/undo.branch b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/undo.branch
deleted file mode 100644
index 331d858..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/undo.branch
+++ /dev/null
@@ -1 +0,0 @@
-default
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/undo.desc b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/undo.desc
deleted file mode 100644
index 48a1e39..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/undo.desc
+++ /dev/null
@@ -1,3 +0,0 @@
-0
-pull
-https://code.google.com/p/go.net
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/undo.dirstate b/eBook/examples/chapter_15/code.google.com/p/go.net/.hg/undo.dirstate
deleted file mode 100644
index e69de29..0000000
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/.hgignore b/eBook/examples/chapter_15/code.google.com/p/go.net/.hgignore
deleted file mode 100644
index 571db5f..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/.hgignore
+++ /dev/null
@@ -1,2 +0,0 @@
-syntax:glob
-last-change
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/AUTHORS b/eBook/examples/chapter_15/code.google.com/p/go.net/AUTHORS
deleted file mode 100644
index 15167cd..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/AUTHORS
+++ /dev/null
@@ -1,3 +0,0 @@
-# This source code refers to The Go Authors for copyright purposes.
-# The master list of authors is in the main Go distribution,
-# visible at http://tip.golang.org/AUTHORS.
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/CONTRIBUTORS b/eBook/examples/chapter_15/code.google.com/p/go.net/CONTRIBUTORS
deleted file mode 100644
index 1c4577e..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/CONTRIBUTORS
+++ /dev/null
@@ -1,3 +0,0 @@
-# This source code was written by the Go contributors.
-# The master list of contributors is in the main Go distribution,
-# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/LICENSE b/eBook/examples/chapter_15/code.google.com/p/go.net/LICENSE
deleted file mode 100644
index 6a66aea..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/README b/eBook/examples/chapter_15/code.google.com/p/go.net/README
deleted file mode 100644
index 6b13d8e..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/README
+++ /dev/null
@@ -1,3 +0,0 @@
-This repository holds supplementary Go networking libraries.
-
-To submit changes to this repository, see http://golang.org/doc/contribute.html.
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/codereview.cfg b/eBook/examples/chapter_15/code.google.com/p/go.net/codereview.cfg
deleted file mode 100644
index e3eb47c..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/codereview.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-defaultcc: golang-dev@googlegroups.com
-contributors: http://go.googlecode.com/hg/CONTRIBUTORS
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/dict/dict.go b/eBook/examples/chapter_15/code.google.com/p/go.net/dict/dict.go
deleted file mode 100644
index e7f5290..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/dict/dict.go
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package dict implements the Dictionary Server Protocol
-// as defined in RFC 2229.
-package dict
-
-import (
- "net/textproto"
- "strconv"
- "strings"
-)
-
-// A Client represents a client connection to a dictionary server.
-type Client struct {
- text *textproto.Conn
-}
-
-// Dial returns a new client connected to a dictionary server at
-// addr on the given network.
-func Dial(network, addr string) (*Client, error) {
- text, err := textproto.Dial(network, addr)
- if err != nil {
- return nil, err
- }
- _, _, err = text.ReadCodeLine(220)
- if err != nil {
- text.Close()
- return nil, err
- }
- return &Client{text: text}, nil
-}
-
-// Close closes the connection to the dictionary server.
-func (c *Client) Close() error {
- return c.text.Close()
-}
-
-// A Dict represents a dictionary available on the server.
-type Dict struct {
- Name string // short name of dictionary
- Desc string // long description
-}
-
-// Dicts returns a list of the dictionaries available on the server.
-func (c *Client) Dicts() ([]Dict, error) {
- id, err := c.text.Cmd("SHOW DB")
- if err != nil {
- return nil, err
- }
-
- c.text.StartResponse(id)
- defer c.text.EndResponse(id)
-
- _, _, err = c.text.ReadCodeLine(110)
- if err != nil {
- return nil, err
- }
- lines, err := c.text.ReadDotLines()
- if err != nil {
- return nil, err
- }
- _, _, err = c.text.ReadCodeLine(250)
-
- dicts := make([]Dict, len(lines))
- for i := range dicts {
- d := &dicts[i]
- a, _ := fields(lines[i])
- if len(a) < 2 {
- return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
- }
- d.Name = a[0]
- d.Desc = a[1]
- }
- return dicts, err
-}
-
-// A Defn represents a definition.
-type Defn struct {
- Dict Dict // Dict where definition was found
- Word string // Word being defined
- Text []byte // Definition text, typically multiple lines
-}
-
-// Define requests the definition of the given word.
-// The argument dict names the dictionary to use,
-// the Name field of a Dict returned by Dicts.
-//
-// The special dictionary name "*" means to look in all the
-// server's dictionaries.
-// The special dictionary name "!" means to look in all the
-// server's dictionaries in turn, stopping after finding the word
-// in one of them.
-func (c *Client) Define(dict, word string) ([]*Defn, error) {
- id, err := c.text.Cmd("DEFINE %s %q", dict, word)
- if err != nil {
- return nil, err
- }
-
- c.text.StartResponse(id)
- defer c.text.EndResponse(id)
-
- _, line, err := c.text.ReadCodeLine(150)
- if err != nil {
- return nil, err
- }
- a, _ := fields(line)
- if len(a) < 1 {
- return nil, textproto.ProtocolError("malformed response: " + line)
- }
- n, err := strconv.Atoi(a[0])
- if err != nil {
- return nil, textproto.ProtocolError("invalid definition count: " + a[0])
- }
- def := make([]*Defn, n)
- for i := 0; i < n; i++ {
- _, line, err = c.text.ReadCodeLine(151)
- if err != nil {
- return nil, err
- }
- a, _ := fields(line)
- if len(a) < 3 {
- // skip it, to keep protocol in sync
- i--
- n--
- def = def[0:n]
- continue
- }
- d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
- d.Text, err = c.text.ReadDotBytes()
- if err != nil {
- return nil, err
- }
- def[i] = d
- }
- _, _, err = c.text.ReadCodeLine(250)
- return def, err
-}
-
-// Fields returns the fields in s.
-// Fields are space separated unquoted words
-// or quoted with single or double quote.
-func fields(s string) ([]string, error) {
- var v []string
- i := 0
- for {
- for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
- i++
- }
- if i >= len(s) {
- break
- }
- if s[i] == '"' || s[i] == '\'' {
- q := s[i]
- // quoted string
- var j int
- for j = i + 1; ; j++ {
- if j >= len(s) {
- return nil, textproto.ProtocolError("malformed quoted string")
- }
- if s[j] == '\\' {
- j++
- continue
- }
- if s[j] == q {
- j++
- break
- }
- }
- v = append(v, unquote(s[i+1:j-1]))
- i = j
- } else {
- // atom
- var j int
- for j = i; j < len(s); j++ {
- if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
- break
- }
- }
- v = append(v, s[i:j])
- i = j
- }
- if i < len(s) {
- c := s[i]
- if c != ' ' && c != '\t' {
- return nil, textproto.ProtocolError("quotes not on word boundaries")
- }
- }
- }
- return v, nil
-}
-
-func unquote(s string) string {
- if strings.Index(s, "\\") < 0 {
- return s
- }
- b := []byte(s)
- w := 0
- for r := 0; r < len(b); r++ {
- c := b[r]
- if c == '\\' {
- r++
- c = b[r]
- }
- b[w] = c
- w++
- }
- return string(b[0:w])
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/read.go b/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/read.go
deleted file mode 100644
index 4830a1d..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/read.go
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package spdy
-
-import (
- "compress/zlib"
- "encoding/binary"
- "io"
- "net/http"
- "strings"
-)
-
-func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) error {
- return f.readSynStreamFrame(h, frame)
-}
-
-func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) error {
- return f.readSynReplyFrame(h, frame)
-}
-
-func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) error {
- frame.CFHeader = h
- if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
- return err
- }
- if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil {
- return err
- }
- return nil
-}
-
-func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) error {
- frame.CFHeader = h
- var numSettings uint32
- if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil {
- return err
- }
- frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings)
- for i := uint32(0); i < numSettings; i++ {
- if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil {
- return err
- }
- frame.FlagIdValues[i].Flag = SettingsFlag((frame.FlagIdValues[i].Id & 0xff000000) >> 24)
- frame.FlagIdValues[i].Id &= 0xffffff
- if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Value); err != nil {
- return err
- }
- }
- return nil
-}
-
-func (frame *NoopFrame) read(h ControlFrameHeader, f *Framer) error {
- frame.CFHeader = h
- return nil
-}
-
-func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) error {
- frame.CFHeader = h
- if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil {
- return err
- }
- return nil
-}
-
-func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) error {
- frame.CFHeader = h
- if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil {
- return err
- }
- return nil
-}
-
-func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) error {
- return f.readHeadersFrame(h, frame)
-}
-
-func newControlFrame(frameType ControlFrameType) (controlFrame, error) {
- ctor, ok := cframeCtor[frameType]
- if !ok {
- return nil, &Error{Err: InvalidControlFrame}
- }
- return ctor(), nil
-}
-
-var cframeCtor = map[ControlFrameType]func() controlFrame{
- TypeSynStream: func() controlFrame { return new(SynStreamFrame) },
- TypeSynReply: func() controlFrame { return new(SynReplyFrame) },
- TypeRstStream: func() controlFrame { return new(RstStreamFrame) },
- TypeSettings: func() controlFrame { return new(SettingsFrame) },
- TypeNoop: func() controlFrame { return new(NoopFrame) },
- TypePing: func() controlFrame { return new(PingFrame) },
- TypeGoAway: func() controlFrame { return new(GoAwayFrame) },
- TypeHeaders: func() controlFrame { return new(HeadersFrame) },
- // TODO(willchan): Add TypeWindowUpdate
-}
-
-func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) error {
- if f.headerDecompressor != nil {
- f.headerReader.N = payloadSize
- return nil
- }
- f.headerReader = io.LimitedReader{R: f.r, N: payloadSize}
- decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(HeaderDictionary))
- if err != nil {
- return err
- }
- f.headerDecompressor = decompressor
- return nil
-}
-
-// ReadFrame reads SPDY encoded data and returns a decompressed Frame.
-func (f *Framer) ReadFrame() (Frame, error) {
- var firstWord uint32
- if err := binary.Read(f.r, binary.BigEndian, &firstWord); err != nil {
- return nil, err
- }
- if (firstWord & 0x80000000) != 0 {
- frameType := ControlFrameType(firstWord & 0xffff)
- version := uint16(0x7fff & (firstWord >> 16))
- return f.parseControlFrame(version, frameType)
- }
- return f.parseDataFrame(firstWord & 0x7fffffff)
-}
-
-func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (Frame, error) {
- var length uint32
- if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
- return nil, err
- }
- flags := ControlFlags((length & 0xff000000) >> 24)
- length &= 0xffffff
- header := ControlFrameHeader{version, frameType, flags, length}
- cframe, err := newControlFrame(frameType)
- if err != nil {
- return nil, err
- }
- if err = cframe.read(header, f); err != nil {
- return nil, err
- }
- return cframe, nil
-}
-
-func parseHeaderValueBlock(r io.Reader, streamId uint32) (http.Header, error) {
- var numHeaders uint16
- if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil {
- return nil, err
- }
- var e error
- h := make(http.Header, int(numHeaders))
- for i := 0; i < int(numHeaders); i++ {
- var length uint16
- if err := binary.Read(r, binary.BigEndian, &length); err != nil {
- return nil, err
- }
- nameBytes := make([]byte, length)
- if _, err := io.ReadFull(r, nameBytes); err != nil {
- return nil, err
- }
- name := string(nameBytes)
- if name != strings.ToLower(name) {
- e = &Error{UnlowercasedHeaderName, streamId}
- name = strings.ToLower(name)
- }
- if h[name] != nil {
- e = &Error{DuplicateHeaders, streamId}
- }
- if err := binary.Read(r, binary.BigEndian, &length); err != nil {
- return nil, err
- }
- value := make([]byte, length)
- if _, err := io.ReadFull(r, value); err != nil {
- return nil, err
- }
- valueList := strings.Split(string(value), "\x00")
- for _, v := range valueList {
- h.Add(name, v)
- }
- }
- if e != nil {
- return h, e
- }
- return h, nil
-}
-
-func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) error {
- frame.CFHeader = h
- var err error
- if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
- return err
- }
- if err = binary.Read(f.r, binary.BigEndian, &frame.AssociatedToStreamId); err != nil {
- return err
- }
- if err = binary.Read(f.r, binary.BigEndian, &frame.Priority); err != nil {
- return err
- }
- frame.Priority >>= 14
-
- reader := f.r
- if !f.headerCompressionDisabled {
- f.uncorkHeaderDecompressor(int64(h.length - 10))
- reader = f.headerDecompressor
- }
-
- frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
- if !f.headerCompressionDisabled && ((err == io.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
- err = &Error{WrongCompressedPayloadSize, 0}
- }
- if err != nil {
- return err
- }
- // Remove this condition when we bump Version to 3.
- if Version >= 3 {
- for h := range frame.Headers {
- if invalidReqHeaders[h] {
- return &Error{InvalidHeaderPresent, frame.StreamId}
- }
- }
- }
- return nil
-}
-
-func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) error {
- frame.CFHeader = h
- var err error
- if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
- return err
- }
- var unused uint16
- if err = binary.Read(f.r, binary.BigEndian, &unused); err != nil {
- return err
- }
- reader := f.r
- if !f.headerCompressionDisabled {
- f.uncorkHeaderDecompressor(int64(h.length - 6))
- reader = f.headerDecompressor
- }
- frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
- if !f.headerCompressionDisabled && ((err == io.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
- err = &Error{WrongCompressedPayloadSize, 0}
- }
- if err != nil {
- return err
- }
- // Remove this condition when we bump Version to 3.
- if Version >= 3 {
- for h := range frame.Headers {
- if invalidRespHeaders[h] {
- return &Error{InvalidHeaderPresent, frame.StreamId}
- }
- }
- }
- return nil
-}
-
-func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) error {
- frame.CFHeader = h
- var err error
- if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
- return err
- }
- var unused uint16
- if err = binary.Read(f.r, binary.BigEndian, &unused); err != nil {
- return err
- }
- reader := f.r
- if !f.headerCompressionDisabled {
- f.uncorkHeaderDecompressor(int64(h.length - 6))
- reader = f.headerDecompressor
- }
- frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
- if !f.headerCompressionDisabled && ((err == io.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
- err = &Error{WrongCompressedPayloadSize, 0}
- }
- if err != nil {
- return err
- }
-
- // Remove this condition when we bump Version to 3.
- if Version >= 3 {
- var invalidHeaders map[string]bool
- if frame.StreamId%2 == 0 {
- invalidHeaders = invalidReqHeaders
- } else {
- invalidHeaders = invalidRespHeaders
- }
- for h := range frame.Headers {
- if invalidHeaders[h] {
- return &Error{InvalidHeaderPresent, frame.StreamId}
- }
- }
- }
- return nil
-}
-
-func (f *Framer) parseDataFrame(streamId uint32) (*DataFrame, error) {
- var length uint32
- if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
- return nil, err
- }
- var frame DataFrame
- frame.StreamId = streamId
- frame.Flags = DataFlags(length >> 24)
- length &= 0xffffff
- frame.Data = make([]byte, length)
- if _, err := io.ReadFull(f.r, frame.Data); err != nil {
- return nil, err
- }
- return &frame, nil
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/spdy_test.go b/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/spdy_test.go
deleted file mode 100644
index c1cad4b..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/spdy_test.go
+++ /dev/null
@@ -1,497 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package spdy
-
-import (
- "bytes"
- "io"
- "net/http"
- "reflect"
- "testing"
-)
-
-func TestHeaderParsing(t *testing.T) {
- headers := http.Header{
- "Url": []string{"http://www.google.com/"},
- "Method": []string{"get"},
- "Version": []string{"http/1.1"},
- }
- var headerValueBlockBuf bytes.Buffer
- writeHeaderValueBlock(&headerValueBlockBuf, headers)
-
- const bogusStreamId = 1
- newHeaders, err := parseHeaderValueBlock(&headerValueBlockBuf, bogusStreamId)
- if err != nil {
- t.Fatal("parseHeaderValueBlock:", err)
- }
-
- if !reflect.DeepEqual(headers, newHeaders) {
- t.Fatal("got: ", newHeaders, "\nwant: ", headers)
- }
-}
-
-func TestCreateParseSynStreamFrame(t *testing.T) {
- buffer := new(bytes.Buffer)
- framer := &Framer{
- headerCompressionDisabled: true,
- w: buffer,
- headerBuf: new(bytes.Buffer),
- r: buffer,
- }
- synStreamFrame := SynStreamFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypeSynStream,
- },
- Headers: http.Header{
- "Url": []string{"http://www.google.com/"},
- "Method": []string{"get"},
- "Version": []string{"http/1.1"},
- },
- }
- if err := framer.WriteFrame(&synStreamFrame); err != nil {
- t.Fatal("WriteFrame without compression:", err)
- }
- frame, err := framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame without compression:", err)
- }
- parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
- t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
- }
-
- // Test again with compression
- buffer.Reset()
- framer, err = NewFramer(buffer, buffer)
- if err != nil {
- t.Fatal("Failed to create new framer:", err)
- }
- if err := framer.WriteFrame(&synStreamFrame); err != nil {
- t.Fatal("WriteFrame with compression:", err)
- }
- frame, err = framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame with compression:", err)
- }
- parsedSynStreamFrame, ok = frame.(*SynStreamFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
- t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
- }
-}
-
-func TestCreateParseSynReplyFrame(t *testing.T) {
- buffer := new(bytes.Buffer)
- framer := &Framer{
- headerCompressionDisabled: true,
- w: buffer,
- headerBuf: new(bytes.Buffer),
- r: buffer,
- }
- synReplyFrame := SynReplyFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypeSynReply,
- },
- Headers: http.Header{
- "Url": []string{"http://www.google.com/"},
- "Method": []string{"get"},
- "Version": []string{"http/1.1"},
- },
- }
- if err := framer.WriteFrame(&synReplyFrame); err != nil {
- t.Fatal("WriteFrame without compression:", err)
- }
- frame, err := framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame without compression:", err)
- }
- parsedSynReplyFrame, ok := frame.(*SynReplyFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) {
- t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame)
- }
-
- // Test again with compression
- buffer.Reset()
- framer, err = NewFramer(buffer, buffer)
- if err != nil {
- t.Fatal("Failed to create new framer:", err)
- }
- if err := framer.WriteFrame(&synReplyFrame); err != nil {
- t.Fatal("WriteFrame with compression:", err)
- }
- frame, err = framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame with compression:", err)
- }
- parsedSynReplyFrame, ok = frame.(*SynReplyFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) {
- t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame)
- }
-}
-
-func TestCreateParseRstStream(t *testing.T) {
- buffer := new(bytes.Buffer)
- framer, err := NewFramer(buffer, buffer)
- if err != nil {
- t.Fatal("Failed to create new framer:", err)
- }
- rstStreamFrame := RstStreamFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypeRstStream,
- },
- StreamId: 1,
- Status: InvalidStream,
- }
- if err := framer.WriteFrame(&rstStreamFrame); err != nil {
- t.Fatal("WriteFrame:", err)
- }
- frame, err := framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame:", err)
- }
- parsedRstStreamFrame, ok := frame.(*RstStreamFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(rstStreamFrame, *parsedRstStreamFrame) {
- t.Fatal("got: ", *parsedRstStreamFrame, "\nwant: ", rstStreamFrame)
- }
-}
-
-func TestCreateParseSettings(t *testing.T) {
- buffer := new(bytes.Buffer)
- framer, err := NewFramer(buffer, buffer)
- if err != nil {
- t.Fatal("Failed to create new framer:", err)
- }
- settingsFrame := SettingsFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypeSettings,
- },
- FlagIdValues: []SettingsFlagIdValue{
- {FlagSettingsPersistValue, SettingsCurrentCwnd, 10},
- {FlagSettingsPersisted, SettingsUploadBandwidth, 1},
- },
- }
- if err := framer.WriteFrame(&settingsFrame); err != nil {
- t.Fatal("WriteFrame:", err)
- }
- frame, err := framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame:", err)
- }
- parsedSettingsFrame, ok := frame.(*SettingsFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(settingsFrame, *parsedSettingsFrame) {
- t.Fatal("got: ", *parsedSettingsFrame, "\nwant: ", settingsFrame)
- }
-}
-
-func TestCreateParseNoop(t *testing.T) {
- buffer := new(bytes.Buffer)
- framer, err := NewFramer(buffer, buffer)
- if err != nil {
- t.Fatal("Failed to create new framer:", err)
- }
- noopFrame := NoopFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypeNoop,
- },
- }
- if err := framer.WriteFrame(&noopFrame); err != nil {
- t.Fatal("WriteFrame:", err)
- }
- frame, err := framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame:", err)
- }
- parsedNoopFrame, ok := frame.(*NoopFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(noopFrame, *parsedNoopFrame) {
- t.Fatal("got: ", *parsedNoopFrame, "\nwant: ", noopFrame)
- }
-}
-
-func TestCreateParsePing(t *testing.T) {
- buffer := new(bytes.Buffer)
- framer, err := NewFramer(buffer, buffer)
- if err != nil {
- t.Fatal("Failed to create new framer:", err)
- }
- pingFrame := PingFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypePing,
- },
- Id: 31337,
- }
- if err := framer.WriteFrame(&pingFrame); err != nil {
- t.Fatal("WriteFrame:", err)
- }
- frame, err := framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame:", err)
- }
- parsedPingFrame, ok := frame.(*PingFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(pingFrame, *parsedPingFrame) {
- t.Fatal("got: ", *parsedPingFrame, "\nwant: ", pingFrame)
- }
-}
-
-func TestCreateParseGoAway(t *testing.T) {
- buffer := new(bytes.Buffer)
- framer, err := NewFramer(buffer, buffer)
- if err != nil {
- t.Fatal("Failed to create new framer:", err)
- }
- goAwayFrame := GoAwayFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypeGoAway,
- },
- LastGoodStreamId: 31337,
- }
- if err := framer.WriteFrame(&goAwayFrame); err != nil {
- t.Fatal("WriteFrame:", err)
- }
- frame, err := framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame:", err)
- }
- parsedGoAwayFrame, ok := frame.(*GoAwayFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(goAwayFrame, *parsedGoAwayFrame) {
- t.Fatal("got: ", *parsedGoAwayFrame, "\nwant: ", goAwayFrame)
- }
-}
-
-func TestCreateParseHeadersFrame(t *testing.T) {
- buffer := new(bytes.Buffer)
- framer := &Framer{
- headerCompressionDisabled: true,
- w: buffer,
- headerBuf: new(bytes.Buffer),
- r: buffer,
- }
- headersFrame := HeadersFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypeHeaders,
- },
- }
- headersFrame.Headers = http.Header{
- "Url": []string{"http://www.google.com/"},
- "Method": []string{"get"},
- "Version": []string{"http/1.1"},
- }
- if err := framer.WriteFrame(&headersFrame); err != nil {
- t.Fatal("WriteFrame without compression:", err)
- }
- frame, err := framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame without compression:", err)
- }
- parsedHeadersFrame, ok := frame.(*HeadersFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
- t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
- }
-
- // Test again with compression
- buffer.Reset()
- framer, err = NewFramer(buffer, buffer)
- if err := framer.WriteFrame(&headersFrame); err != nil {
- t.Fatal("WriteFrame with compression:", err)
- }
- frame, err = framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame with compression:", err)
- }
- parsedHeadersFrame, ok = frame.(*HeadersFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
- t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
- }
-}
-
-func TestCreateParseDataFrame(t *testing.T) {
- buffer := new(bytes.Buffer)
- framer, err := NewFramer(buffer, buffer)
- if err != nil {
- t.Fatal("Failed to create new framer:", err)
- }
- dataFrame := DataFrame{
- StreamId: 1,
- Data: []byte{'h', 'e', 'l', 'l', 'o'},
- }
- if err := framer.WriteFrame(&dataFrame); err != nil {
- t.Fatal("WriteFrame:", err)
- }
- frame, err := framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame:", err)
- }
- parsedDataFrame, ok := frame.(*DataFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(dataFrame, *parsedDataFrame) {
- t.Fatal("got: ", *parsedDataFrame, "\nwant: ", dataFrame)
- }
-}
-
-func TestCompressionContextAcrossFrames(t *testing.T) {
- buffer := new(bytes.Buffer)
- framer, err := NewFramer(buffer, buffer)
- if err != nil {
- t.Fatal("Failed to create new framer:", err)
- }
- headersFrame := HeadersFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypeHeaders,
- },
- Headers: http.Header{
- "Url": []string{"http://www.google.com/"},
- "Method": []string{"get"},
- "Version": []string{"http/1.1"},
- },
- }
- if err := framer.WriteFrame(&headersFrame); err != nil {
- t.Fatal("WriteFrame (HEADERS):", err)
- }
- synStreamFrame := SynStreamFrame{ControlFrameHeader{Version, TypeSynStream, 0, 0}, 0, 0, 0, nil}
- synStreamFrame.Headers = http.Header{
- "Url": []string{"http://www.google.com/"},
- "Method": []string{"get"},
- "Version": []string{"http/1.1"},
- }
- if err := framer.WriteFrame(&synStreamFrame); err != nil {
- t.Fatal("WriteFrame (SYN_STREAM):", err)
- }
- frame, err := framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame (HEADERS):", err, buffer.Bytes())
- }
- parsedHeadersFrame, ok := frame.(*HeadersFrame)
- if !ok {
- t.Fatalf("expected HeadersFrame; got %T %v", frame, frame)
- }
- if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
- t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
- }
- frame, err = framer.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame (SYN_STREAM):", err, buffer.Bytes())
- }
- parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
- if !ok {
- t.Fatalf("expected SynStreamFrame; got %T %v", frame, frame)
- }
- if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
- t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
- }
-}
-
-func TestMultipleSPDYFrames(t *testing.T) {
- // Initialize the framers.
- pr1, pw1 := io.Pipe()
- pr2, pw2 := io.Pipe()
- writer, err := NewFramer(pw1, pr2)
- if err != nil {
- t.Fatal("Failed to create writer:", err)
- }
- reader, err := NewFramer(pw2, pr1)
- if err != nil {
- t.Fatal("Failed to create reader:", err)
- }
-
- // Set up the frames we're actually transferring.
- headersFrame := HeadersFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypeHeaders,
- },
- Headers: http.Header{
- "Url": []string{"http://www.google.com/"},
- "Method": []string{"get"},
- "Version": []string{"http/1.1"},
- },
- }
- synStreamFrame := SynStreamFrame{
- CFHeader: ControlFrameHeader{
- version: Version,
- frameType: TypeSynStream,
- },
- Headers: http.Header{
- "Url": []string{"http://www.google.com/"},
- "Method": []string{"get"},
- "Version": []string{"http/1.1"},
- },
- }
-
- // Start the goroutines to write the frames.
- go func() {
- if err := writer.WriteFrame(&headersFrame); err != nil {
- t.Fatal("WriteFrame (HEADERS): ", err)
- }
- if err := writer.WriteFrame(&synStreamFrame); err != nil {
- t.Fatal("WriteFrame (SYN_STREAM): ", err)
- }
- }()
-
- // Read the frames and verify they look as expected.
- frame, err := reader.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame (HEADERS): ", err)
- }
- parsedHeadersFrame, ok := frame.(*HeadersFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type:", frame)
- }
- if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
- t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
- }
- frame, err = reader.ReadFrame()
- if err != nil {
- t.Fatal("ReadFrame (SYN_STREAM):", err)
- }
- parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
- if !ok {
- t.Fatal("Parsed incorrect frame type.")
- }
- if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
- t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
- }
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/types.go b/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/types.go
deleted file mode 100644
index 7c57d36..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/types.go
+++ /dev/null
@@ -1,369 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package spdy
-
-import (
- "bytes"
- "compress/zlib"
- "io"
- "net/http"
-)
-
-// Data Frame Format
-// +----------------------------------+
-// |0| Stream-ID (31bits) |
-// +----------------------------------+
-// | flags (8) | Length (24 bits) |
-// +----------------------------------+
-// | Data |
-// +----------------------------------+
-//
-// Control Frame Format
-// +----------------------------------+
-// |1| Version(15bits) | Type(16bits) |
-// +----------------------------------+
-// | flags (8) | Length (24 bits) |
-// +----------------------------------+
-// | Data |
-// +----------------------------------+
-//
-// Control Frame: SYN_STREAM
-// +----------------------------------+
-// |1|000000000000001|0000000000000001|
-// +----------------------------------+
-// | flags (8) | Length (24 bits) | >= 12
-// +----------------------------------+
-// |X| Stream-ID(31bits) |
-// +----------------------------------+
-// |X|Associated-To-Stream-ID (31bits)|
-// +----------------------------------+
-// |Pri| unused | Length (16bits)|
-// +----------------------------------+
-//
-// Control Frame: SYN_REPLY
-// +----------------------------------+
-// |1|000000000000001|0000000000000010|
-// +----------------------------------+
-// | flags (8) | Length (24 bits) | >= 8
-// +----------------------------------+
-// |X| Stream-ID(31bits) |
-// +----------------------------------+
-// | unused (16 bits)| Length (16bits)|
-// +----------------------------------+
-//
-// Control Frame: RST_STREAM
-// +----------------------------------+
-// |1|000000000000001|0000000000000011|
-// +----------------------------------+
-// | flags (8) | Length (24 bits) | >= 4
-// +----------------------------------+
-// |X| Stream-ID(31bits) |
-// +----------------------------------+
-// | Status code (32 bits) |
-// +----------------------------------+
-//
-// Control Frame: SETTINGS
-// +----------------------------------+
-// |1|000000000000001|0000000000000100|
-// +----------------------------------+
-// | flags (8) | Length (24 bits) |
-// +----------------------------------+
-// | # of entries (32) |
-// +----------------------------------+
-//
-// Control Frame: NOOP
-// +----------------------------------+
-// |1|000000000000001|0000000000000101|
-// +----------------------------------+
-// | flags (8) | Length (24 bits) | = 0
-// +----------------------------------+
-//
-// Control Frame: PING
-// +----------------------------------+
-// |1|000000000000001|0000000000000110|
-// +----------------------------------+
-// | flags (8) | Length (24 bits) | = 4
-// +----------------------------------+
-// | Unique id (32 bits) |
-// +----------------------------------+
-//
-// Control Frame: GOAWAY
-// +----------------------------------+
-// |1|000000000000001|0000000000000111|
-// +----------------------------------+
-// | flags (8) | Length (24 bits) | = 4
-// +----------------------------------+
-// |X| Last-accepted-stream-id |
-// +----------------------------------+
-//
-// Control Frame: HEADERS
-// +----------------------------------+
-// |1|000000000000001|0000000000001000|
-// +----------------------------------+
-// | flags (8) | Length (24 bits) | >= 8
-// +----------------------------------+
-// |X| Stream-ID (31 bits) |
-// +----------------------------------+
-// | unused (16 bits)| Length (16bits)|
-// +----------------------------------+
-//
-// Control Frame: WINDOW_UPDATE
-// +----------------------------------+
-// |1|000000000000001|0000000000001001|
-// +----------------------------------+
-// | flags (8) | Length (24 bits) | = 8
-// +----------------------------------+
-// |X| Stream-ID (31 bits) |
-// +----------------------------------+
-// | Delta-Window-Size (32 bits) |
-// +----------------------------------+
-
-// Version is the protocol version number that this package implements.
-const Version = 2
-
-// ControlFrameType stores the type field in a control frame header.
-type ControlFrameType uint16
-
-// Control frame type constants
-const (
- TypeSynStream ControlFrameType = 0x0001
- TypeSynReply = 0x0002
- TypeRstStream = 0x0003
- TypeSettings = 0x0004
- TypeNoop = 0x0005
- TypePing = 0x0006
- TypeGoAway = 0x0007
- TypeHeaders = 0x0008
- TypeWindowUpdate = 0x0009
-)
-
-// ControlFlags are the flags that can be set on a control frame.
-type ControlFlags uint8
-
-const (
- ControlFlagFin ControlFlags = 0x01
-)
-
-// DataFlags are the flags that can be set on a data frame.
-type DataFlags uint8
-
-const (
- DataFlagFin DataFlags = 0x01
- DataFlagCompressed = 0x02
-)
-
-// MaxDataLength is the maximum number of bytes that can be stored in one frame.
-const MaxDataLength = 1<<24 - 1
-
-// Frame is a single SPDY frame in its unpacked in-memory representation. Use
-// Framer to read and write it.
-type Frame interface {
- write(f *Framer) error
-}
-
-// ControlFrameHeader contains all the fields in a control frame header,
-// in its unpacked in-memory representation.
-type ControlFrameHeader struct {
- // Note, high bit is the "Control" bit.
- version uint16
- frameType ControlFrameType
- Flags ControlFlags
- length uint32
-}
-
-type controlFrame interface {
- Frame
- read(h ControlFrameHeader, f *Framer) error
-}
-
-// SynStreamFrame is the unpacked, in-memory representation of a SYN_STREAM
-// frame.
-type SynStreamFrame struct {
- CFHeader ControlFrameHeader
- StreamId uint32
- AssociatedToStreamId uint32
- // Note, only 2 highest bits currently used
- // Rest of Priority is unused.
- Priority uint16
- Headers http.Header
-}
-
-// SynReplyFrame is the unpacked, in-memory representation of a SYN_REPLY frame.
-type SynReplyFrame struct {
- CFHeader ControlFrameHeader
- StreamId uint32
- Headers http.Header
-}
-
-// StatusCode represents the status that led to a RST_STREAM
-type StatusCode uint32
-
-const (
- ProtocolError StatusCode = 1
- InvalidStream = 2
- RefusedStream = 3
- UnsupportedVersion = 4
- Cancel = 5
- InternalError = 6
- FlowControlError = 7
-)
-
-// RstStreamFrame is the unpacked, in-memory representation of a RST_STREAM
-// frame.
-type RstStreamFrame struct {
- CFHeader ControlFrameHeader
- StreamId uint32
- Status StatusCode
-}
-
-// SettingsFlag represents a flag in a SETTINGS frame.
-type SettingsFlag uint8
-
-const (
- FlagSettingsPersistValue SettingsFlag = 0x1
- FlagSettingsPersisted = 0x2
-)
-
-// SettingsFlag represents the id of an id/value pair in a SETTINGS frame.
-type SettingsId uint32
-
-const (
- SettingsUploadBandwidth SettingsId = 1
- SettingsDownloadBandwidth = 2
- SettingsRoundTripTime = 3
- SettingsMaxConcurrentStreams = 4
- SettingsCurrentCwnd = 5
-)
-
-// SettingsFlagIdValue is the unpacked, in-memory representation of the
-// combined flag/id/value for a setting in a SETTINGS frame.
-type SettingsFlagIdValue struct {
- Flag SettingsFlag
- Id SettingsId
- Value uint32
-}
-
-// SettingsFrame is the unpacked, in-memory representation of a SPDY
-// SETTINGS frame.
-type SettingsFrame struct {
- CFHeader ControlFrameHeader
- FlagIdValues []SettingsFlagIdValue
-}
-
-// NoopFrame is the unpacked, in-memory representation of a NOOP frame.
-type NoopFrame struct {
- CFHeader ControlFrameHeader
-}
-
-// PingFrame is the unpacked, in-memory representation of a PING frame.
-type PingFrame struct {
- CFHeader ControlFrameHeader
- Id uint32
-}
-
-// GoAwayFrame is the unpacked, in-memory representation of a GOAWAY frame.
-type GoAwayFrame struct {
- CFHeader ControlFrameHeader
- LastGoodStreamId uint32
-}
-
-// HeadersFrame is the unpacked, in-memory representation of a HEADERS frame.
-type HeadersFrame struct {
- CFHeader ControlFrameHeader
- StreamId uint32
- Headers http.Header
-}
-
-// DataFrame is the unpacked, in-memory representation of a DATA frame.
-type DataFrame struct {
- // Note, high bit is the "Control" bit. Should be 0 for data frames.
- StreamId uint32
- Flags DataFlags
- Data []byte
-}
-
-// HeaderDictionary is the dictionary sent to the zlib compressor/decompressor.
-// Even though the specification states there is no null byte at the end, Chrome sends it.
-const HeaderDictionary = "optionsgetheadpostputdeletetrace" +
- "acceptaccept-charsetaccept-encodingaccept-languageauthorizationexpectfromhost" +
- "if-modified-sinceif-matchif-none-matchif-rangeif-unmodifiedsince" +
- "max-forwardsproxy-authorizationrangerefererteuser-agent" +
- "100101200201202203204205206300301302303304305306307400401402403404405406407408409410411412413414415416417500501502503504505" +
- "accept-rangesageetaglocationproxy-authenticatepublicretry-after" +
- "servervarywarningwww-authenticateallowcontent-basecontent-encodingcache-control" +
- "connectiondatetrailertransfer-encodingupgradeviawarning" +
- "content-languagecontent-lengthcontent-locationcontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookie" +
- "MondayTuesdayWednesdayThursdayFridaySaturdaySunday" +
- "JanFebMarAprMayJunJulAugSepOctNovDec" +
- "chunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-age" +
- "charset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl\x00"
-
-// A SPDY specific error.
-type ErrorCode string
-
-const (
- UnlowercasedHeaderName ErrorCode = "header was not lowercased"
- DuplicateHeaders ErrorCode = "multiple headers with same name"
- WrongCompressedPayloadSize ErrorCode = "compressed payload size was incorrect"
- UnknownFrameType ErrorCode = "unknown frame type"
- InvalidControlFrame ErrorCode = "invalid control frame"
- InvalidDataFrame ErrorCode = "invalid data frame"
- InvalidHeaderPresent ErrorCode = "frame contained invalid header"
-)
-
-// Error contains both the type of error and additional values. StreamId is 0
-// if Error is not associated with a stream.
-type Error struct {
- Err ErrorCode
- StreamId uint32
-}
-
-func (e *Error) Error() string {
- return string(e.Err)
-}
-
-var invalidReqHeaders = map[string]bool{
- "Connection": true,
- "Keep-Alive": true,
- "Proxy-Connection": true,
- "Transfer-Encoding": true,
-}
-
-var invalidRespHeaders = map[string]bool{
- "Connection": true,
- "Keep-Alive": true,
- "Transfer-Encoding": true,
-}
-
-// Framer handles serializing/deserializing SPDY frames, including compressing/
-// decompressing payloads.
-type Framer struct {
- headerCompressionDisabled bool
- w io.Writer
- headerBuf *bytes.Buffer
- headerCompressor *zlib.Writer
- r io.Reader
- headerReader io.LimitedReader
- headerDecompressor io.ReadCloser
-}
-
-// NewFramer allocates a new Framer for a given SPDY connection, repesented by
-// a io.Writer and io.Reader. Note that Framer will read and write individual fields
-// from/to the Reader and Writer, so the caller should pass in an appropriately
-// buffered implementation to optimize performance.
-func NewFramer(w io.Writer, r io.Reader) (*Framer, error) {
- compressBuf := new(bytes.Buffer)
- compressor, err := zlib.NewWriterLevelDict(compressBuf, zlib.BestCompression, []byte(HeaderDictionary))
- if err != nil {
- return nil, err
- }
- framer := &Framer{
- w: w,
- headerBuf: compressBuf,
- headerCompressor: compressor,
- r: r,
- }
- return framer, nil
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/write.go b/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/write.go
deleted file mode 100644
index 3dd2ca1..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/spdy/write.go
+++ /dev/null
@@ -1,285 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package spdy
-
-import (
- "encoding/binary"
- "io"
- "net/http"
- "strings"
-)
-
-func (frame *SynStreamFrame) write(f *Framer) error {
- return f.writeSynStreamFrame(frame)
-}
-
-func (frame *SynReplyFrame) write(f *Framer) error {
- return f.writeSynReplyFrame(frame)
-}
-
-func (frame *RstStreamFrame) write(f *Framer) (err error) {
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeRstStream
- frame.CFHeader.length = 8
-
- // Serialize frame to Writer
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
- return
- }
- return
-}
-
-func (frame *SettingsFrame) write(f *Framer) (err error) {
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeSettings
- frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
-
- // Serialize frame to Writer
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
- return
- }
- for _, flagIdValue := range frame.FlagIdValues {
- flagId := (uint32(flagIdValue.Flag) << 24) | uint32(flagIdValue.Id)
- if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil {
- return
- }
- }
- return
-}
-
-func (frame *NoopFrame) write(f *Framer) error {
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeNoop
-
- // Serialize frame to Writer
- return writeControlFrameHeader(f.w, frame.CFHeader)
-}
-
-func (frame *PingFrame) write(f *Framer) (err error) {
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypePing
- frame.CFHeader.length = 4
-
- // Serialize frame to Writer
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil {
- return
- }
- return
-}
-
-func (frame *GoAwayFrame) write(f *Framer) (err error) {
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeGoAway
- frame.CFHeader.length = 4
-
- // Serialize frame to Writer
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil {
- return
- }
- return nil
-}
-
-func (frame *HeadersFrame) write(f *Framer) error {
- return f.writeHeadersFrame(frame)
-}
-
-func (frame *DataFrame) write(f *Framer) error {
- return f.writeDataFrame(frame)
-}
-
-// WriteFrame writes a frame.
-func (f *Framer) WriteFrame(frame Frame) error {
- return frame.write(f)
-}
-
-func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) error {
- if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil {
- return err
- }
- if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil {
- return err
- }
- flagsAndLength := (uint32(h.Flags) << 24) | h.length
- if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil {
- return err
- }
- return nil
-}
-
-func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err error) {
- n = 0
- if err = binary.Write(w, binary.BigEndian, uint16(len(h))); err != nil {
- return
- }
- n += 2
- for name, values := range h {
- if err = binary.Write(w, binary.BigEndian, uint16(len(name))); err != nil {
- return
- }
- n += 2
- name = strings.ToLower(name)
- if _, err = io.WriteString(w, name); err != nil {
- return
- }
- n += len(name)
- v := strings.Join(values, "\x00")
- if err = binary.Write(w, binary.BigEndian, uint16(len(v))); err != nil {
- return
- }
- n += 2
- if _, err = io.WriteString(w, v); err != nil {
- return
- }
- n += len(v)
- }
- return
-}
-
-func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err error) {
- // Marshal the headers.
- var writer io.Writer = f.headerBuf
- if !f.headerCompressionDisabled {
- writer = f.headerCompressor
- }
- if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
- return
- }
- if !f.headerCompressionDisabled {
- f.headerCompressor.Flush()
- }
-
- // Set ControlFrameHeader
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeSynStream
- frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
-
- // Serialize frame to Writer
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return err
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return err
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil {
- return err
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<14); err != nil {
- return err
- }
- if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
- return err
- }
- f.headerBuf.Reset()
- return nil
-}
-
-func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err error) {
- // Marshal the headers.
- var writer io.Writer = f.headerBuf
- if !f.headerCompressionDisabled {
- writer = f.headerCompressor
- }
- if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
- return
- }
- if !f.headerCompressionDisabled {
- f.headerCompressor.Flush()
- }
-
- // Set ControlFrameHeader
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeSynReply
- frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6)
-
- // Serialize frame to Writer
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil {
- return
- }
- if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
- return
- }
- f.headerBuf.Reset()
- return
-}
-
-func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err error) {
- // Marshal the headers.
- var writer io.Writer = f.headerBuf
- if !f.headerCompressionDisabled {
- writer = f.headerCompressor
- }
- if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
- return
- }
- if !f.headerCompressionDisabled {
- f.headerCompressor.Flush()
- }
-
- // Set ControlFrameHeader
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeHeaders
- frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6)
-
- // Serialize frame to Writer
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil {
- return
- }
- if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
- return
- }
- f.headerBuf.Reset()
- return
-}
-
-func (f *Framer) writeDataFrame(frame *DataFrame) (err error) {
- // Validate DataFrame
- if frame.StreamId&0x80000000 != 0 || len(frame.Data) >= 0x0f000000 {
- return &Error{InvalidDataFrame, frame.StreamId}
- }
-
- // Serialize frame to Writer
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return
- }
- flagsAndLength := (uint32(frame.Flags) << 24) | uint32(len(frame.Data))
- if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
- return
- }
- if _, err = f.w.Write(frame.Data); err != nil {
- return
- }
-
- return nil
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/client.go b/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/client.go
deleted file mode 100644
index 1b82e9c..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/client.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bufio"
- "crypto/tls"
- "io"
- "net"
- "net/url"
-)
-
-// DialError is an error that occurs while dialling a websocket server.
-type DialError struct {
- *Config
- Err error
-}
-
-func (e *DialError) Error() string {
- return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error()
-}
-
-// NewConfig creates a new WebSocket config for client connection.
-func NewConfig(server, origin string) (config *Config, err error) {
- config = new(Config)
- config.Version = ProtocolVersionHybi13
- config.Location, err = url.ParseRequestURI(server)
- if err != nil {
- return
- }
- config.Origin, err = url.ParseRequestURI(origin)
- if err != nil {
- return
- }
- return
-}
-
-// NewClient creates a new WebSocket client connection over rwc.
-func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
- br := bufio.NewReader(rwc)
- bw := bufio.NewWriter(rwc)
- switch config.Version {
- case ProtocolVersionHixie75:
- err = hixie75ClientHandshake(config, br, bw)
- case ProtocolVersionHixie76, ProtocolVersionHybi00:
- err = hixie76ClientHandshake(config, br, bw)
- case ProtocolVersionHybi08, ProtocolVersionHybi13:
- err = hybiClientHandshake(config, br, bw)
- default:
- err = ErrBadProtocolVersion
- }
- if err != nil {
- return
- }
- buf := bufio.NewReadWriter(br, bw)
- switch config.Version {
- case ProtocolVersionHixie75, ProtocolVersionHixie76, ProtocolVersionHybi00:
- ws = newHixieClientConn(config, buf, rwc)
- case ProtocolVersionHybi08, ProtocolVersionHybi13:
- ws = newHybiClientConn(config, buf, rwc)
- }
- return
-}
-
-/*
-Dial opens a new client connection to a WebSocket.
-
-A trivial example client:
-
- package main
-
- import (
- "log"
- "net/http"
- "strings"
- "websocket"
- )
-
- func main() {
- origin := "http://localhost/"
- url := "ws://localhost/ws"
- ws, err := websocket.Dial(url, "", origin)
- if err != nil {
- log.Fatal(err)
- }
- if _, err := ws.Write([]byte("hello, world!\n")); err != nil {
- log.Fatal(err)
- }
- var msg = make([]byte, 512);
- if n, err := ws.Read(msg); err != nil {
- log.Fatal(err)
- }
- // use msg[0:n]
- }
-*/
-func Dial(url_, protocol, origin string) (ws *Conn, err error) {
- config, err := NewConfig(url_, origin)
- if err != nil {
- return nil, err
- }
- return DialConfig(config)
-}
-
-// DialConfig opens a new client connection to a WebSocket with a config.
-func DialConfig(config *Config) (ws *Conn, err error) {
- var client net.Conn
- if config.Location == nil {
- return nil, &DialError{config, ErrBadWebSocketLocation}
- }
- if config.Origin == nil {
- return nil, &DialError{config, ErrBadWebSocketOrigin}
- }
- switch config.Location.Scheme {
- case "ws":
- client, err = net.Dial("tcp", config.Location.Host)
-
- case "wss":
- client, err = tls.Dial("tcp", config.Location.Host, config.TlsConfig)
-
- default:
- err = ErrBadScheme
- }
- if err != nil {
- goto Error
- }
-
- ws, err = NewClient(config, client)
- if err != nil {
- goto Error
- }
- return
-
-Error:
- return nil, &DialError{config, err}
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hixie.go b/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hixie.go
deleted file mode 100644
index 6d215b9..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hixie.go
+++ /dev/null
@@ -1,695 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-// This file implements a protocol of Hixie draft version 75 and 76
-// (draft 76 equals to hybi 00)
-
-import (
- "bufio"
- "bytes"
- "crypto/md5"
- "encoding/binary"
- "fmt"
- "io"
- "io/ioutil"
- "math/rand"
- "net/http"
- "net/url"
- "strconv"
- "strings"
-)
-
-// An aray of characters to be randomly inserted to construct Sec-WebSocket-Key
-// value. It holds characters from ranges U+0021 to U+002F and U+003A to U+007E.
-// See Step 21 in Section 4.1 Opening handshake.
-// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#page-22
-var secKeyRandomChars [0x30 - 0x21 + 0x7F - 0x3A]byte
-
-func init() {
- i := 0
- for ch := byte(0x21); ch < 0x30; ch++ {
- secKeyRandomChars[i] = ch
- i++
- }
- for ch := byte(0x3a); ch < 0x7F; ch++ {
- secKeyRandomChars[i] = ch
- i++
- }
-}
-
-type byteReader interface {
- ReadByte() (byte, error)
-}
-
-// readHixieLength reads frame length for frame type 0x80-0xFF
-// as defined in Hixie draft.
-// See section 4.2 Data framing.
-// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#section-4.2
-func readHixieLength(r byteReader) (length int64, lengthFields []byte, err error) {
- for {
- c, err := r.ReadByte()
- if err != nil {
- return 0, nil, err
- }
- lengthFields = append(lengthFields, c)
- length = length*128 + int64(c&0x7f)
- if c&0x80 == 0 {
- break
- }
- }
- return
-}
-
-// A hixieLengthFrameReader is a reader for frame type 0x80-0xFF
-// as defined in hixie draft.
-type hixieLengthFrameReader struct {
- reader io.Reader
- FrameType byte
- Length int64
- header *bytes.Buffer
- length int
-}
-
-func (frame *hixieLengthFrameReader) Read(msg []byte) (n int, err error) {
- return frame.reader.Read(msg)
-}
-
-func (frame *hixieLengthFrameReader) PayloadType() byte {
- if frame.FrameType == '\xff' && frame.Length == 0 {
- return CloseFrame
- }
- return UnknownFrame
-}
-
-func (frame *hixieLengthFrameReader) HeaderReader() io.Reader {
- if frame.header == nil {
- return nil
- }
- if frame.header.Len() == 0 {
- frame.header = nil
- return nil
- }
- return frame.header
-}
-
-func (frame *hixieLengthFrameReader) TrailerReader() io.Reader { return nil }
-
-func (frame *hixieLengthFrameReader) Len() (n int) { return frame.length }
-
-// A HixieSentinelFrameReader is a reader for frame type 0x00-0x7F
-// as defined in hixie draft.
-type hixieSentinelFrameReader struct {
- reader *bufio.Reader
- FrameType byte
- header *bytes.Buffer
- data []byte
- seenTrailer bool
- trailer *bytes.Buffer
-}
-
-func (frame *hixieSentinelFrameReader) Read(msg []byte) (n int, err error) {
- if len(frame.data) == 0 {
- if frame.seenTrailer {
- return 0, io.EOF
- }
- frame.data, err = frame.reader.ReadSlice('\xff')
- if err == nil {
- frame.seenTrailer = true
- frame.data = frame.data[:len(frame.data)-1] // trim \xff
- frame.trailer = bytes.NewBuffer([]byte{0xff})
- }
- }
- n = copy(msg, frame.data)
- frame.data = frame.data[n:]
- return n, err
-}
-
-func (frame *hixieSentinelFrameReader) PayloadType() byte {
- if frame.FrameType == 0 {
- return TextFrame
- }
- return UnknownFrame
-}
-
-func (frame *hixieSentinelFrameReader) HeaderReader() io.Reader {
- if frame.header == nil {
- return nil
- }
- if frame.header.Len() == 0 {
- frame.header = nil
- return nil
- }
- return frame.header
-}
-
-func (frame *hixieSentinelFrameReader) TrailerReader() io.Reader {
- if frame.trailer == nil {
- return nil
- }
- if frame.trailer.Len() == 0 {
- frame.trailer = nil
- return nil
- }
- return frame.trailer
-}
-
-func (frame *hixieSentinelFrameReader) Len() int { return -1 }
-
-// A HixieFrameReaderFactory creates new frame reader based on its frame type.
-type hixieFrameReaderFactory struct {
- *bufio.Reader
-}
-
-func (buf hixieFrameReaderFactory) NewFrameReader() (r frameReader, err error) {
- var header []byte
- var b byte
- b, err = buf.ReadByte()
- if err != nil {
- return
- }
- header = append(header, b)
- if b&0x80 == 0x80 {
- length, lengthFields, err := readHixieLength(buf.Reader)
- if err != nil {
- return nil, err
- }
- if length == 0 {
- return nil, io.EOF
- }
- header = append(header, lengthFields...)
- return &hixieLengthFrameReader{
- reader: io.LimitReader(buf.Reader, length),
- FrameType: b,
- Length: length,
- header: bytes.NewBuffer(header)}, err
- }
- return &hixieSentinelFrameReader{
- reader: buf.Reader,
- FrameType: b,
- header: bytes.NewBuffer(header)}, err
-}
-
-type hixiFrameWriter struct {
- writer *bufio.Writer
-}
-
-func (frame *hixiFrameWriter) Write(msg []byte) (n int, err error) {
- frame.writer.WriteByte(0)
- frame.writer.Write(msg)
- frame.writer.WriteByte(0xff)
- err = frame.writer.Flush()
- return len(msg), err
-}
-
-func (frame *hixiFrameWriter) Close() error { return nil }
-
-type hixiFrameWriterFactory struct {
- *bufio.Writer
-}
-
-func (buf hixiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) {
- if payloadType != TextFrame {
- return nil, ErrNotSupported
- }
- return &hixiFrameWriter{writer: buf.Writer}, nil
-}
-
-type hixiFrameHandler struct {
- conn *Conn
-}
-
-func (handler *hixiFrameHandler) HandleFrame(frame frameReader) (r frameReader, err error) {
- if header := frame.HeaderReader(); header != nil {
- io.Copy(ioutil.Discard, header)
- }
- if frame.PayloadType() != TextFrame {
- io.Copy(ioutil.Discard, frame)
- return nil, nil
- }
- return frame, nil
-}
-
-func (handler *hixiFrameHandler) WriteClose(_ int) (err error) {
- handler.conn.wio.Lock()
- defer handler.conn.wio.Unlock()
- closingFrame := []byte{'\xff', '\x00'}
- handler.conn.buf.Write(closingFrame)
- return handler.conn.buf.Flush()
-}
-
-// newHixiConn creates a new WebSocket connection speaking hixie draft protocol.
-func newHixieConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
- if buf == nil {
- br := bufio.NewReader(rwc)
- bw := bufio.NewWriter(rwc)
- buf = bufio.NewReadWriter(br, bw)
- }
- ws := &Conn{config: config, request: request, buf: buf, rwc: rwc,
- frameReaderFactory: hixieFrameReaderFactory{buf.Reader},
- frameWriterFactory: hixiFrameWriterFactory{buf.Writer},
- PayloadType: TextFrame}
- ws.frameHandler = &hixiFrameHandler{ws}
- return ws
-}
-
-// getChallengeResponse computes the expected response from the
-// challenge as described in section 5.1 Opening Handshake steps 42 to
-// 43 of http://www.whatwg.org/specs/web-socket-protocol/
-func getChallengeResponse(number1, number2 uint32, key3 []byte) (expected []byte, err error) {
- // 41. Let /challenge/ be the concatenation of /number_1/, expressed
- // a big-endian 32 bit integer, /number_2/, expressed in a big-
- // endian 32 bit integer, and the eight bytes of /key_3/ in the
- // order they were sent to the wire.
- challenge := make([]byte, 16)
- binary.BigEndian.PutUint32(challenge[0:], number1)
- binary.BigEndian.PutUint32(challenge[4:], number2)
- copy(challenge[8:], key3)
-
- // 42. Let /expected/ be the MD5 fingerprint of /challenge/ as a big-
- // endian 128 bit string.
- h := md5.New()
- if _, err = h.Write(challenge); err != nil {
- return
- }
- expected = h.Sum(nil)
- return
-}
-
-// Generates handshake key as described in 4.1 Opening handshake step 16 to 22.
-// cf. http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
-func generateKeyNumber() (key string, number uint32) {
- // 16. Let /spaces_n/ be a random integer from 1 to 12 inclusive.
- spaces := rand.Intn(12) + 1
-
- // 17. Let /max_n/ be the largest integer not greater than
- // 4,294,967,295 divided by /spaces_n/
- max := int(4294967295 / uint32(spaces))
-
- // 18. Let /number_n/ be a random integer from 0 to /max_n/ inclusive.
- number = uint32(rand.Intn(max + 1))
-
- // 19. Let /product_n/ be the result of multiplying /number_n/ and
- // /spaces_n/ together.
- product := number * uint32(spaces)
-
- // 20. Let /key_n/ be a string consisting of /product_n/, expressed
- // in base ten using the numerals in the range U+0030 DIGIT ZERO (0)
- // to U+0039 DIGIT NINE (9).
- key = fmt.Sprintf("%d", product)
-
- // 21. Insert between one and twelve random characters from the ranges
- // U+0021 to U+002F and U+003A to U+007E into /key_n/ at random
- // positions.
- n := rand.Intn(12) + 1
- for i := 0; i < n; i++ {
- pos := rand.Intn(len(key)) + 1
- ch := secKeyRandomChars[rand.Intn(len(secKeyRandomChars))]
- key = key[0:pos] + string(ch) + key[pos:]
- }
-
- // 22. Insert /spaces_n/ U+0020 SPACE characters into /key_n/ at random
- // positions other than the start or end of the string.
- for i := 0; i < spaces; i++ {
- pos := rand.Intn(len(key)-1) + 1
- key = key[0:pos] + " " + key[pos:]
- }
-
- return
-}
-
-// Generates handshake key_3 as described in 4.1 Opening handshake step 26.
-// cf. http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
-func generateKey3() (key []byte) {
- // 26. Let /key3/ be a string consisting of eight random bytes (or
- // equivalently, a random 64 bit integer encoded in big-endian order).
- key = make([]byte, 8)
- for i := 0; i < 8; i++ {
- key[i] = byte(rand.Intn(256))
- }
- return
-}
-
-// Cilent handhake described in (soon obsolete)
-// draft-ietf-hybi-thewebsocket-protocol-00
-// (draft-hixie-thewebsocket-protocol-76)
-func hixie76ClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
- switch config.Version {
- case ProtocolVersionHixie76, ProtocolVersionHybi00:
- default:
- panic("wrong protocol version.")
- }
- // 4.1. Opening handshake.
- // Step 5. send a request line.
- bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
-
- // Step 6-14. push request headers in fields.
- fields := []string{
- "Upgrade: WebSocket\r\n",
- "Connection: Upgrade\r\n",
- "Host: " + config.Location.Host + "\r\n",
- "Origin: " + config.Origin.String() + "\r\n",
- }
- if len(config.Protocol) > 0 {
- if len(config.Protocol) != 1 {
- return ErrBadWebSocketProtocol
- }
- fields = append(fields, "Sec-WebSocket-Protocol: "+config.Protocol[0]+"\r\n")
- }
- // TODO(ukai): Step 15. send cookie if any.
-
- // Step 16-23. generate keys and push Sec-WebSocket-Key in fields.
- key1, number1 := generateKeyNumber()
- key2, number2 := generateKeyNumber()
- if config.handshakeData != nil {
- key1 = config.handshakeData["key1"]
- n, err := strconv.ParseUint(config.handshakeData["number1"], 10, 32)
- if err != nil {
- panic(err)
- }
- number1 = uint32(n)
- key2 = config.handshakeData["key2"]
- n, err = strconv.ParseUint(config.handshakeData["number2"], 10, 32)
- if err != nil {
- panic(err)
- }
- number2 = uint32(n)
- }
- fields = append(fields, "Sec-WebSocket-Key1: "+key1+"\r\n")
- fields = append(fields, "Sec-WebSocket-Key2: "+key2+"\r\n")
-
- // Step 24. shuffle fields and send them out.
- for i := 1; i < len(fields); i++ {
- j := rand.Intn(i)
- fields[i], fields[j] = fields[j], fields[i]
- }
- for i := 0; i < len(fields); i++ {
- bw.WriteString(fields[i])
- }
- // Step 25. send CRLF.
- bw.WriteString("\r\n")
-
- // Step 26. generate 8 bytes random key.
- key3 := generateKey3()
- if config.handshakeData != nil {
- key3 = []byte(config.handshakeData["key3"])
- }
- // Step 27. send it out.
- bw.Write(key3)
- if err = bw.Flush(); err != nil {
- return
- }
-
- // Step 28-29, 32-40. read response from server.
- resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
- if err != nil {
- return err
- }
- // Step 30. check response code is 101.
- if resp.StatusCode != 101 {
- return ErrBadStatus
- }
-
- // Step 41. check websocket headers.
- if resp.Header.Get("Upgrade") != "WebSocket" ||
- strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
- return ErrBadUpgrade
- }
-
- if resp.Header.Get("Sec-Websocket-Origin") != config.Origin.String() {
- return ErrBadWebSocketOrigin
- }
-
- if resp.Header.Get("Sec-Websocket-Location") != config.Location.String() {
- return ErrBadWebSocketLocation
- }
-
- if len(config.Protocol) > 0 && resp.Header.Get("Sec-Websocket-Protocol") != config.Protocol[0] {
- return ErrBadWebSocketProtocol
- }
-
- // Step 42-43. get expected data from challenge data.
- expected, err := getChallengeResponse(number1, number2, key3)
- if err != nil {
- return err
- }
-
- // Step 44. read 16 bytes from server.
- reply := make([]byte, 16)
- if _, err = io.ReadFull(br, reply); err != nil {
- return err
- }
-
- // Step 45. check the reply equals to expected data.
- if !bytes.Equal(expected, reply) {
- return ErrChallengeResponse
- }
- // WebSocket connection is established.
- return
-}
-
-// Client Handshake described in (soon obsolete)
-// draft-hixie-thewebsocket-protocol-75.
-func hixie75ClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
- if config.Version != ProtocolVersionHixie75 {
- panic("wrong protocol version.")
- }
- bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
- bw.WriteString("Upgrade: WebSocket\r\n")
- bw.WriteString("Connection: Upgrade\r\n")
- bw.WriteString("Host: " + config.Location.Host + "\r\n")
- bw.WriteString("Origin: " + config.Origin.String() + "\r\n")
- if len(config.Protocol) > 0 {
- if len(config.Protocol) != 1 {
- return ErrBadWebSocketProtocol
- }
- bw.WriteString("WebSocket-Protocol: " + config.Protocol[0] + "\r\n")
- }
- bw.WriteString("\r\n")
- bw.Flush()
- resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
- if err != nil {
- return
- }
- if resp.Status != "101 Web Socket Protocol Handshake" {
- return ErrBadStatus
- }
- if resp.Header.Get("Upgrade") != "WebSocket" ||
- resp.Header.Get("Connection") != "Upgrade" {
- return ErrBadUpgrade
- }
- if resp.Header.Get("Websocket-Origin") != config.Origin.String() {
- return ErrBadWebSocketOrigin
- }
- if resp.Header.Get("Websocket-Location") != config.Location.String() {
- return ErrBadWebSocketLocation
- }
- if len(config.Protocol) > 0 && resp.Header.Get("Websocket-Protocol") != config.Protocol[0] {
- return ErrBadWebSocketProtocol
- }
- return
-}
-
-// newHixieClientConn returns new WebSocket connection speaking hixie draft protocol.
-func newHixieClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
- return newHixieConn(config, buf, rwc, nil)
-}
-
-// Gets key number from Sec-WebSocket-Key: field as described
-// in 5.2 Sending the server's opening handshake, 4.
-func getKeyNumber(s string) (r uint32) {
- // 4. Let /key-number_n/ be the digits (characters in the range
- // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9)) in /key_1/,
- // interpreted as a base ten integer, ignoring all other characters
- // in /key_n/.
- r = 0
- for i := 0; i < len(s); i++ {
- if s[i] >= '0' && s[i] <= '9' {
- r = r*10 + uint32(s[i]) - '0'
- }
- }
- return
-}
-
-// A Hixie76ServerHandshaker performs a server handshake using
-// hixie draft 76 protocol.
-type hixie76ServerHandshaker struct {
- *Config
- challengeResponse []byte
-}
-
-func (c *hixie76ServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
- c.Version = ProtocolVersionHybi00
- if req.Method != "GET" {
- return http.StatusMethodNotAllowed, ErrBadRequestMethod
- }
- // HTTP version can be safely ignored.
-
- if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
- strings.ToLower(req.Header.Get("Connection")) != "upgrade" {
- return http.StatusBadRequest, ErrNotWebSocket
- }
-
- // TODO(ukai): check Host
- c.Origin, err = url.ParseRequestURI(req.Header.Get("Origin"))
- if err != nil {
- return http.StatusBadRequest, err
- }
-
- key1 := req.Header.Get("Sec-Websocket-Key1")
- if key1 == "" {
- return http.StatusBadRequest, ErrChallengeResponse
- }
- key2 := req.Header.Get("Sec-Websocket-Key2")
- if key2 == "" {
- return http.StatusBadRequest, ErrChallengeResponse
- }
- key3 := make([]byte, 8)
- if _, err := io.ReadFull(buf, key3); err != nil {
- return http.StatusBadRequest, ErrChallengeResponse
- }
-
- var scheme string
- if req.TLS != nil {
- scheme = "wss"
- } else {
- scheme = "ws"
- }
- c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
- if err != nil {
- return http.StatusBadRequest, err
- }
-
- // Step 4. get key number in Sec-WebSocket-Key fields.
- keyNumber1 := getKeyNumber(key1)
- keyNumber2 := getKeyNumber(key2)
-
- // Step 5. get number of spaces in Sec-WebSocket-Key fields.
- space1 := uint32(strings.Count(key1, " "))
- space2 := uint32(strings.Count(key2, " "))
- if space1 == 0 || space2 == 0 {
- return http.StatusBadRequest, ErrChallengeResponse
- }
-
- // Step 6. key number must be an integral multiple of spaces.
- if keyNumber1%space1 != 0 || keyNumber2%space2 != 0 {
- return http.StatusBadRequest, ErrChallengeResponse
- }
-
- // Step 7. let part be key number divided by spaces.
- part1 := keyNumber1 / space1
- part2 := keyNumber2 / space2
-
- // Step 8. let challenge be concatenation of part1, part2 and key3.
- // Step 9. get MD5 fingerprint of challenge.
- c.challengeResponse, err = getChallengeResponse(part1, part2, key3)
- if err != nil {
- return http.StatusInternalServerError, err
- }
- protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
- protocols := strings.Split(protocol, ",")
- for i := 0; i < len(protocols); i++ {
- c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
- }
-
- return http.StatusSwitchingProtocols, nil
-}
-
-func (c *hixie76ServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
- if len(c.Protocol) > 0 {
- if len(c.Protocol) != 1 {
- return ErrBadWebSocketProtocol
- }
- }
-
- // Step 10. send response status line.
- buf.WriteString("HTTP/1.1 101 WebSocket Protocol Handshake\r\n")
- // Step 11. send response headers.
- buf.WriteString("Upgrade: WebSocket\r\n")
- buf.WriteString("Connection: Upgrade\r\n")
- buf.WriteString("Sec-WebSocket-Origin: " + c.Origin.String() + "\r\n")
- buf.WriteString("Sec-WebSocket-Location: " + c.Location.String() + "\r\n")
- if len(c.Protocol) > 0 {
- buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
- }
- // Step 12. send CRLF.
- buf.WriteString("\r\n")
- // Step 13. send response data.
- buf.Write(c.challengeResponse)
- return buf.Flush()
-}
-
-func (c *hixie76ServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn) {
- return newHixieServerConn(c.Config, buf, rwc, request)
-}
-
-// A hixie75ServerHandshaker performs a server handshake using
-// hixie draft 75 protocol.
-type hixie75ServerHandshaker struct {
- *Config
-}
-
-func (c *hixie75ServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
- c.Version = ProtocolVersionHixie75
- if req.Method != "GET" || req.Proto != "HTTP/1.1" {
- return http.StatusMethodNotAllowed, ErrBadRequestMethod
- }
- if req.Header.Get("Upgrade") != "WebSocket" {
- return http.StatusBadRequest, ErrNotWebSocket
- }
- if req.Header.Get("Connection") != "Upgrade" {
- return http.StatusBadRequest, ErrNotWebSocket
- }
- c.Origin, err = url.ParseRequestURI(strings.TrimSpace(req.Header.Get("Origin")))
- if err != nil {
- return http.StatusBadRequest, err
- }
-
- var scheme string
- if req.TLS != nil {
- scheme = "wss"
- } else {
- scheme = "ws"
- }
- c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
- if err != nil {
- return http.StatusBadRequest, err
- }
- protocol := strings.TrimSpace(req.Header.Get("Websocket-Protocol"))
- protocols := strings.Split(protocol, ",")
- for i := 0; i < len(protocols); i++ {
- c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
- }
-
- return http.StatusSwitchingProtocols, nil
-}
-
-func (c *hixie75ServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
- if len(c.Protocol) > 0 {
- if len(c.Protocol) != 1 {
- return ErrBadWebSocketProtocol
- }
- }
-
- buf.WriteString("HTTP/1.1 101 Web Socket Protocol Handshake\r\n")
- buf.WriteString("Upgrade: WebSocket\r\n")
- buf.WriteString("Connection: Upgrade\r\n")
- buf.WriteString("WebSocket-Origin: " + c.Origin.String() + "\r\n")
- buf.WriteString("WebSocket-Location: " + c.Location.String() + "\r\n")
- if len(c.Protocol) > 0 {
- buf.WriteString("WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
- }
- buf.WriteString("\r\n")
- return buf.Flush()
-}
-
-func (c *hixie75ServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn) {
- return newHixieServerConn(c.Config, buf, rwc, request)
-}
-
-// newHixieServerConn returns a new WebSocket connection speaking hixie draft protocol.
-func newHixieServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
- return newHixieConn(config, buf, rwc, request)
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hixie_test.go b/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hixie_test.go
deleted file mode 100644
index 8f387dd..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hixie_test.go
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strings"
- "testing"
-)
-
-// Test the getChallengeResponse function with values from section
-// 5.1 of the specification steps 18, 26, and 43 from
-// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
-func TestHixie76Challenge(t *testing.T) {
- var part1 uint32 = 777007543
- var part2 uint32 = 114997259
- key3 := []byte{0x47, 0x30, 0x22, 0x2D, 0x5A, 0x3F, 0x47, 0x58}
- expected := []byte("0st3Rl&q-2ZU^weu")
-
- response, err := getChallengeResponse(part1, part2, key3)
- if err != nil {
- t.Errorf("getChallengeResponse: returned error %v", err)
- return
- }
- if !bytes.Equal(expected, response) {
- t.Errorf("getChallengeResponse: expected %q got %q", expected, response)
- }
-}
-
-func TestHixie76ClientHandshake(t *testing.T) {
- b := bytes.NewBuffer([]byte{})
- bw := bufio.NewWriter(b)
- br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 WebSocket Protocol Handshake
-Upgrade: WebSocket
-Connection: Upgrade
-Sec-WebSocket-Origin: http://example.com
-Sec-WebSocket-Location: ws://example.com/demo
-Sec-WebSocket-Protocol: sample
-
-8jKS'y:G*Co,Wxa-`))
-
- var err error
- config := new(Config)
- config.Location, err = url.ParseRequestURI("ws://example.com/demo")
- if err != nil {
- t.Fatal("location url", err)
- }
- config.Origin, err = url.ParseRequestURI("http://example.com")
- if err != nil {
- t.Fatal("origin url", err)
- }
- config.Protocol = append(config.Protocol, "sample")
- config.Version = ProtocolVersionHixie76
-
- config.handshakeData = map[string]string{
- "key1": "4 @1 46546xW%0l 1 5",
- "number1": "829309203",
- "key2": "12998 5 Y3 1 .P00",
- "number2": "259970620",
- "key3": "^n:ds[4U",
- }
- err = hixie76ClientHandshake(config, br, bw)
- if err != nil {
- t.Errorf("handshake failed: %v", err)
- }
- req, err := http.ReadRequest(bufio.NewReader(b))
- if err != nil {
- t.Fatalf("read request: %v", err)
- }
- if req.Method != "GET" {
- t.Errorf("request method expected GET, but got %q", req.Method)
- }
- if req.URL.Path != "/demo" {
- t.Errorf("request path expected /demo, but got %q", req.URL.Path)
- }
- if req.Proto != "HTTP/1.1" {
- t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto)
- }
- if req.Host != "example.com" {
- t.Errorf("request Host expected example.com, but got %v", req.Host)
- }
- var expectedHeader = map[string]string{
- "Connection": "Upgrade",
- "Upgrade": "WebSocket",
- "Origin": "http://example.com",
- "Sec-Websocket-Key1": config.handshakeData["key1"],
- "Sec-Websocket-Key2": config.handshakeData["key2"],
- "Sec-WebSocket-Protocol": config.Protocol[0],
- }
- for k, v := range expectedHeader {
- if req.Header.Get(k) != v {
- t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k)))
- }
- }
-}
-
-func TestHixie76ServerHandshake(t *testing.T) {
- config := new(Config)
- handshaker := &hixie76ServerHandshaker{Config: config}
- br := bufio.NewReader(strings.NewReader(`GET /demo HTTP/1.1
-Host: example.com
-Connection: Upgrade
-Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
-Sec-WebSocket-Protocol: sample
-Upgrade: WebSocket
-Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
-Origin: http://example.com
-
-^n:ds[4U`))
- req, err := http.ReadRequest(br)
- if err != nil {
- t.Fatal("request", err)
- }
- code, err := handshaker.ReadHandshake(br, req)
- if err != nil {
- t.Errorf("handshake failed: %v", err)
- }
- if code != http.StatusSwitchingProtocols {
- t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code)
- }
- b := bytes.NewBuffer([]byte{})
- bw := bufio.NewWriter(b)
-
- err = handshaker.AcceptHandshake(bw)
- if err != nil {
- t.Errorf("handshake response failed: %v", err)
- }
- expectedResponse := strings.Join([]string{
- "HTTP/1.1 101 WebSocket Protocol Handshake",
- "Upgrade: WebSocket",
- "Connection: Upgrade",
- "Sec-WebSocket-Origin: http://example.com",
- "Sec-WebSocket-Location: ws://example.com/demo",
- "Sec-WebSocket-Protocol: sample",
- "", ""}, "\r\n") + "8jKS'y:G*Co,Wxa-"
- if b.String() != expectedResponse {
- t.Errorf("handshake expected %q but got %q", expectedResponse, b.String())
- }
-}
-
-func TestHixie76SkipLengthFrame(t *testing.T) {
- b := []byte{'\x80', '\x01', 'x', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
- buf := bytes.NewBuffer(b)
- br := bufio.NewReader(buf)
- bw := bufio.NewWriter(buf)
- config := newConfig(t, "/")
- ws := newHixieConn(config, bufio.NewReadWriter(br, bw), nil, nil)
- msg := make([]byte, 5)
- n, err := ws.Read(msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- if !bytes.Equal(b[4:9], msg[0:n]) {
- t.Errorf("Read: expected %q got %q", b[4:9], msg[0:n])
- }
-}
-
-func TestHixie76SkipNoUTF8Frame(t *testing.T) {
- b := []byte{'\x01', 'n', '\xff', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
- buf := bytes.NewBuffer(b)
- br := bufio.NewReader(buf)
- bw := bufio.NewWriter(buf)
- config := newConfig(t, "/")
- ws := newHixieConn(config, bufio.NewReadWriter(br, bw), nil, nil)
- msg := make([]byte, 5)
- n, err := ws.Read(msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- if !bytes.Equal(b[4:9], msg[0:n]) {
- t.Errorf("Read: expected %q got %q", b[4:9], msg[0:n])
- }
-}
-
-func TestHixie76ClosingFrame(t *testing.T) {
- b := []byte{0, 'h', 'e', 'l', 'l', 'o', '\xff'}
- buf := bytes.NewBuffer(b)
- br := bufio.NewReader(buf)
- bw := bufio.NewWriter(buf)
- config := newConfig(t, "/")
- ws := newHixieConn(config, bufio.NewReadWriter(br, bw), nil, nil)
- msg := make([]byte, 5)
- n, err := ws.Read(msg)
- if err != nil {
- t.Errorf("read: %v", err)
- }
- if !bytes.Equal(b[1:6], msg[0:n]) {
- t.Errorf("Read: expected %q got %q", b[1:6], msg[0:n])
- }
- n, err = ws.Read(msg)
- if err != io.EOF {
- t.Errorf("read: %v", err)
- }
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hybi.go b/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hybi.go
deleted file mode 100644
index ab18ffc..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hybi.go
+++ /dev/null
@@ -1,549 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-// This file implements a protocol of hybi draft.
-// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
-
-import (
- "bufio"
- "bytes"
- "crypto/rand"
- "crypto/sha1"
- "encoding/base64"
- "encoding/binary"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "strings"
-)
-
-const (
- websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
-
- closeStatusNormal = 1000
- closeStatusGoingAway = 1001
- closeStatusProtocolError = 1002
- closeStatusUnsupportedData = 1003
- closeStatusFrameTooLarge = 1004
- closeStatusNoStatusRcvd = 1005
- closeStatusAbnormalClosure = 1006
- closeStatusBadMessageData = 1007
- closeStatusPolicyViolation = 1008
- closeStatusTooBigData = 1009
- closeStatusExtensionMismatch = 1010
-
- maxControlFramePayloadLength = 125
-)
-
-var (
- ErrBadMaskingKey = &ProtocolError{"bad masking key"}
- ErrBadPongMessage = &ProtocolError{"bad pong message"}
- ErrBadClosingStatus = &ProtocolError{"bad closing status"}
- ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"}
- ErrNotImplemented = &ProtocolError{"not implemented"}
-)
-
-// A hybiFrameHeader is a frame header as defined in hybi draft.
-type hybiFrameHeader struct {
- Fin bool
- Rsv [3]bool
- OpCode byte
- Length int64
- MaskingKey []byte
-
- data *bytes.Buffer
-}
-
-// A hybiFrameReader is a reader for hybi frame.
-type hybiFrameReader struct {
- reader io.Reader
-
- header hybiFrameHeader
- pos int64
- length int
-}
-
-func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) {
- n, err = frame.reader.Read(msg)
- if err != nil {
- return 0, err
- }
- if frame.header.MaskingKey != nil {
- for i := 0; i < n; i++ {
- msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4]
- frame.pos++
- }
- }
- return n, err
-}
-
-func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode }
-
-func (frame *hybiFrameReader) HeaderReader() io.Reader {
- if frame.header.data == nil {
- return nil
- }
- if frame.header.data.Len() == 0 {
- return nil
- }
- return frame.header.data
-}
-
-func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil }
-
-func (frame *hybiFrameReader) Len() (n int) { return frame.length }
-
-// A hybiFrameReaderFactory creates new frame reader based on its frame type.
-type hybiFrameReaderFactory struct {
- *bufio.Reader
-}
-
-// NewFrameReader reads a frame header from the connection, and creates new reader for the frame.
-// See Section 5.2 Base Frameing protocol for detail.
-// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2
-func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) {
- hybiFrame := new(hybiFrameReader)
- frame = hybiFrame
- var header []byte
- var b byte
- // First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits)
- b, err = buf.ReadByte()
- if err != nil {
- return
- }
- header = append(header, b)
- hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0
- for i := 0; i < 3; i++ {
- j := uint(6 - i)
- hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0
- }
- hybiFrame.header.OpCode = header[0] & 0x0f
-
- // Second byte. Mask/Payload len(7bits)
- b, err = buf.ReadByte()
- if err != nil {
- return
- }
- header = append(header, b)
- mask := (b & 0x80) != 0
- b &= 0x7f
- lengthFields := 0
- switch {
- case b <= 125: // Payload length 7bits.
- hybiFrame.header.Length = int64(b)
- case b == 126: // Payload length 7+16bits
- lengthFields = 2
- case b == 127: // Payload length 7+64bits
- lengthFields = 8
- }
- for i := 0; i < lengthFields; i++ {
- b, err = buf.ReadByte()
- if err != nil {
- return
- }
- header = append(header, b)
- hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b)
- }
- if mask {
- // Masking key. 4 bytes.
- for i := 0; i < 4; i++ {
- b, err = buf.ReadByte()
- if err != nil {
- return
- }
- header = append(header, b)
- hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b)
- }
- }
- hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length)
- hybiFrame.header.data = bytes.NewBuffer(header)
- hybiFrame.length = len(header) + int(hybiFrame.header.Length)
- return
-}
-
-// A HybiFrameWriter is a writer for hybi frame.
-type hybiFrameWriter struct {
- writer *bufio.Writer
-
- header *hybiFrameHeader
-}
-
-func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) {
- var header []byte
- var b byte
- if frame.header.Fin {
- b |= 0x80
- }
- for i := 0; i < 3; i++ {
- if frame.header.Rsv[i] {
- j := uint(6 - i)
- b |= 1 << j
- }
- }
- b |= frame.header.OpCode
- header = append(header, b)
- if frame.header.MaskingKey != nil {
- b = 0x80
- } else {
- b = 0
- }
- lengthFields := 0
- length := len(msg)
- switch {
- case length <= 125:
- b |= byte(length)
- case length < 65536:
- b |= 126
- lengthFields = 2
- default:
- b |= 127
- lengthFields = 8
- }
- header = append(header, b)
- for i := 0; i < lengthFields; i++ {
- j := uint((lengthFields - i - 1) * 8)
- b = byte((length >> j) & 0xff)
- header = append(header, b)
- }
- if frame.header.MaskingKey != nil {
- if len(frame.header.MaskingKey) != 4 {
- return 0, ErrBadMaskingKey
- }
- header = append(header, frame.header.MaskingKey...)
- frame.writer.Write(header)
- var data []byte
-
- for i := 0; i < length; i++ {
- data = append(data, msg[i]^frame.header.MaskingKey[i%4])
- }
- frame.writer.Write(data)
- err = frame.writer.Flush()
- return length, err
- }
- frame.writer.Write(header)
- frame.writer.Write(msg)
- err = frame.writer.Flush()
- return length, err
-}
-
-func (frame *hybiFrameWriter) Close() error { return nil }
-
-type hybiFrameWriterFactory struct {
- *bufio.Writer
- needMaskingKey bool
-}
-
-func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) {
- frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType}
- if buf.needMaskingKey {
- frameHeader.MaskingKey, err = generateMaskingKey()
- if err != nil {
- return nil, err
- }
- }
- return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil
-}
-
-type hybiFrameHandler struct {
- conn *Conn
- payloadType byte
-}
-
-func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (r frameReader, err error) {
- if handler.conn.IsServerConn() {
- // The client MUST mask all frames sent to the server.
- if frame.(*hybiFrameReader).header.MaskingKey == nil {
- handler.WriteClose(closeStatusProtocolError)
- return nil, io.EOF
- }
- } else {
- // The server MUST NOT mask all frames.
- if frame.(*hybiFrameReader).header.MaskingKey != nil {
- handler.WriteClose(closeStatusProtocolError)
- return nil, io.EOF
- }
- }
- if header := frame.HeaderReader(); header != nil {
- io.Copy(ioutil.Discard, header)
- }
- switch frame.PayloadType() {
- case ContinuationFrame:
- frame.(*hybiFrameReader).header.OpCode = handler.payloadType
- case TextFrame, BinaryFrame:
- handler.payloadType = frame.PayloadType()
- case CloseFrame:
- return nil, io.EOF
- case PingFrame:
- pingMsg := make([]byte, maxControlFramePayloadLength)
- n, err := io.ReadFull(frame, pingMsg)
- if err != nil && err != io.ErrUnexpectedEOF {
- return nil, err
- }
- io.Copy(ioutil.Discard, frame)
- n, err = handler.WritePong(pingMsg[:n])
- if err != nil {
- return nil, err
- }
- return nil, nil
- case PongFrame:
- return nil, ErrNotImplemented
- }
- return frame, nil
-}
-
-func (handler *hybiFrameHandler) WriteClose(status int) (err error) {
- handler.conn.wio.Lock()
- defer handler.conn.wio.Unlock()
- w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame)
- if err != nil {
- return err
- }
- msg := make([]byte, 2)
- binary.BigEndian.PutUint16(msg, uint16(status))
- _, err = w.Write(msg)
- w.Close()
- return err
-}
-
-func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) {
- handler.conn.wio.Lock()
- defer handler.conn.wio.Unlock()
- w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame)
- if err != nil {
- return 0, err
- }
- n, err = w.Write(msg)
- w.Close()
- return n, err
-}
-
-// newHybiConn creates a new WebSocket connection speaking hybi draft protocol.
-func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
- if buf == nil {
- br := bufio.NewReader(rwc)
- bw := bufio.NewWriter(rwc)
- buf = bufio.NewReadWriter(br, bw)
- }
- ws := &Conn{config: config, request: request, buf: buf, rwc: rwc,
- frameReaderFactory: hybiFrameReaderFactory{buf.Reader},
- frameWriterFactory: hybiFrameWriterFactory{
- buf.Writer, request == nil},
- PayloadType: TextFrame,
- defaultCloseStatus: closeStatusNormal}
- ws.frameHandler = &hybiFrameHandler{conn: ws}
- return ws
-}
-
-// generateMaskingKey generates a masking key for a frame.
-func generateMaskingKey() (maskingKey []byte, err error) {
- maskingKey = make([]byte, 4)
- if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil {
- return
- }
- return
-}
-
-// genetateNonce geneates a nonce consisting of a randomly selected 16-byte
-// value that has been base64-encoded.
-func generateNonce() (nonce []byte) {
- key := make([]byte, 16)
- if _, err := io.ReadFull(rand.Reader, key); err != nil {
- panic(err)
- }
- nonce = make([]byte, 24)
- base64.StdEncoding.Encode(nonce, key)
- return
-}
-
-// getNonceAccept computes the base64-encoded SHA-1 of the concatenation of
-// the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string.
-func getNonceAccept(nonce []byte) (expected []byte, err error) {
- h := sha1.New()
- if _, err = h.Write(nonce); err != nil {
- return
- }
- if _, err = h.Write([]byte(websocketGUID)); err != nil {
- return
- }
- expected = make([]byte, 28)
- base64.StdEncoding.Encode(expected, h.Sum(nil))
- return
-}
-
-func isHybiVersion(version int) bool {
- switch version {
- case ProtocolVersionHybi08, ProtocolVersionHybi13:
- return true
- default:
- }
- return false
-}
-
-// Client handhake described in draft-ietf-hybi-thewebsocket-protocol-17
-func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
- if !isHybiVersion(config.Version) {
- panic("wrong protocol version.")
- }
-
- bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
-
- bw.WriteString("Host: " + config.Location.Host + "\r\n")
- bw.WriteString("Upgrade: websocket\r\n")
- bw.WriteString("Connection: Upgrade\r\n")
- nonce := generateNonce()
- if config.handshakeData != nil {
- nonce = []byte(config.handshakeData["key"])
- }
- bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n")
- if config.Version == ProtocolVersionHybi13 {
- bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
- } else if config.Version == ProtocolVersionHybi08 {
- bw.WriteString("Sec-WebSocket-Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
- }
- bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n")
- if len(config.Protocol) > 0 {
- bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n")
- }
- // TODO(ukai): send extensions.
- // TODO(ukai): send cookie if any.
-
- bw.WriteString("\r\n")
- if err = bw.Flush(); err != nil {
- return err
- }
-
- resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
- if err != nil {
- return err
- }
- if resp.StatusCode != 101 {
- return ErrBadStatus
- }
- if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" ||
- strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
- return ErrBadUpgrade
- }
- expectedAccept, err := getNonceAccept(nonce)
- if err != nil {
- return err
- }
- if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) {
- return ErrChallengeResponse
- }
- if resp.Header.Get("Sec-WebSocket-Extensions") != "" {
- return ErrUnsupportedExtensions
- }
- offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol")
- if offeredProtocol != "" {
- protocolMatched := false
- for i := 0; i < len(config.Protocol); i++ {
- if config.Protocol[i] == offeredProtocol {
- protocolMatched = true
- break
- }
- }
- if !protocolMatched {
- return ErrBadWebSocketProtocol
- }
- config.Protocol = []string{offeredProtocol}
- }
-
- return nil
-}
-
-// newHybiClientConn creates a client WebSocket connection after handshake.
-func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
- return newHybiConn(config, buf, rwc, nil)
-}
-
-// A HybiServerHandshaker performs a server handshake using hybi draft protocol.
-type hybiServerHandshaker struct {
- *Config
- accept []byte
-}
-
-func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
- c.Version = ProtocolVersionHybi13
- if req.Method != "GET" {
- return http.StatusMethodNotAllowed, ErrBadRequestMethod
- }
- // HTTP version can be safely ignored.
-
- if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
- !strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") {
- return http.StatusBadRequest, ErrNotWebSocket
- }
-
- key := req.Header.Get("Sec-Websocket-Key")
- if key == "" {
- return http.StatusBadRequest, ErrChallengeResponse
- }
- version := req.Header.Get("Sec-Websocket-Version")
- var origin string
- switch version {
- case "13":
- c.Version = ProtocolVersionHybi13
- origin = req.Header.Get("Origin")
- case "8":
- c.Version = ProtocolVersionHybi08
- origin = req.Header.Get("Sec-Websocket-Origin")
- default:
- return http.StatusBadRequest, ErrBadWebSocketVersion
- }
- c.Origin, err = url.ParseRequestURI(origin)
- if err != nil {
- return http.StatusForbidden, err
- }
- var scheme string
- if req.TLS != nil {
- scheme = "wss"
- } else {
- scheme = "ws"
- }
- c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
- if err != nil {
- return http.StatusBadRequest, err
- }
- protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
- protocols := strings.Split(protocol, ",")
- for i := 0; i < len(protocols); i++ {
- c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
- }
- c.accept, err = getNonceAccept([]byte(key))
- if err != nil {
- return http.StatusInternalServerError, err
- }
- return http.StatusSwitchingProtocols, nil
-}
-
-func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
- if len(c.Protocol) > 0 {
- if len(c.Protocol) != 1 {
- return ErrBadWebSocketProtocol
- }
- }
- buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
- buf.WriteString("Upgrade: websocket\r\n")
- buf.WriteString("Connection: Upgrade\r\n")
- buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n")
- if len(c.Protocol) > 0 {
- buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
- }
- // TODO(ukai): support extensions
- buf.WriteString("\r\n")
- return buf.Flush()
-}
-
-func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
- return newHybiServerConn(c.Config, buf, rwc, request)
-}
-
-// newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol.
-func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
- return newHybiConn(config, buf, rwc, request)
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hybi_test.go b/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hybi_test.go
deleted file mode 100644
index 7976054..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/hybi_test.go
+++ /dev/null
@@ -1,584 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "strings"
- "testing"
-)
-
-// Test the getNonceAccept function with values in
-// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
-func TestSecWebSocketAccept(t *testing.T) {
- nonce := []byte("dGhlIHNhbXBsZSBub25jZQ==")
- expected := []byte("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")
- accept, err := getNonceAccept(nonce)
- if err != nil {
- t.Errorf("getNonceAccept: returned error %v", err)
- return
- }
- if !bytes.Equal(expected, accept) {
- t.Errorf("getNonceAccept: expected %q got %q", expected, accept)
- }
-}
-
-func TestHybiClientHandshake(t *testing.T) {
- b := bytes.NewBuffer([]byte{})
- bw := bufio.NewWriter(b)
- br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols
-Upgrade: websocket
-Connection: Upgrade
-Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
-Sec-WebSocket-Protocol: chat
-
-`))
- var err error
- config := new(Config)
- config.Location, err = url.ParseRequestURI("ws://server.example.com/chat")
- if err != nil {
- t.Fatal("location url", err)
- }
- config.Origin, err = url.ParseRequestURI("http://example.com")
- if err != nil {
- t.Fatal("origin url", err)
- }
- config.Protocol = append(config.Protocol, "chat")
- config.Protocol = append(config.Protocol, "superchat")
- config.Version = ProtocolVersionHybi13
-
- config.handshakeData = map[string]string{
- "key": "dGhlIHNhbXBsZSBub25jZQ==",
- }
- err = hybiClientHandshake(config, br, bw)
- if err != nil {
- t.Errorf("handshake failed: %v", err)
- }
- req, err := http.ReadRequest(bufio.NewReader(b))
- if err != nil {
- t.Fatalf("read request: %v", err)
- }
- if req.Method != "GET" {
- t.Errorf("request method expected GET, but got %q", req.Method)
- }
- if req.URL.Path != "/chat" {
- t.Errorf("request path expected /chat, but got %q", req.URL.Path)
- }
- if req.Proto != "HTTP/1.1" {
- t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto)
- }
- if req.Host != "server.example.com" {
- t.Errorf("request Host expected server.example.com, but got %v", req.Host)
- }
- var expectedHeader = map[string]string{
- "Connection": "Upgrade",
- "Upgrade": "websocket",
- "Sec-Websocket-Key": config.handshakeData["key"],
- "Origin": config.Origin.String(),
- "Sec-Websocket-Protocol": "chat, superchat",
- "Sec-Websocket-Version": fmt.Sprintf("%d", ProtocolVersionHybi13),
- }
- for k, v := range expectedHeader {
- if req.Header.Get(k) != v {
- t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k)))
- }
- }
-}
-
-func TestHybiClientHandshakeHybi08(t *testing.T) {
- b := bytes.NewBuffer([]byte{})
- bw := bufio.NewWriter(b)
- br := bufio.NewReader(strings.NewReader(`HTTP/1.1 101 Switching Protocols
-Upgrade: websocket
-Connection: Upgrade
-Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
-Sec-WebSocket-Protocol: chat
-
-`))
- var err error
- config := new(Config)
- config.Location, err = url.ParseRequestURI("ws://server.example.com/chat")
- if err != nil {
- t.Fatal("location url", err)
- }
- config.Origin, err = url.ParseRequestURI("http://example.com")
- if err != nil {
- t.Fatal("origin url", err)
- }
- config.Protocol = append(config.Protocol, "chat")
- config.Protocol = append(config.Protocol, "superchat")
- config.Version = ProtocolVersionHybi08
-
- config.handshakeData = map[string]string{
- "key": "dGhlIHNhbXBsZSBub25jZQ==",
- }
- err = hybiClientHandshake(config, br, bw)
- if err != nil {
- t.Errorf("handshake failed: %v", err)
- }
- req, err := http.ReadRequest(bufio.NewReader(b))
- if err != nil {
- t.Fatalf("read request: %v", err)
- }
- if req.Method != "GET" {
- t.Errorf("request method expected GET, but got %q", req.Method)
- }
- if req.URL.Path != "/chat" {
- t.Errorf("request path expected /demo, but got %q", req.URL.Path)
- }
- if req.Proto != "HTTP/1.1" {
- t.Errorf("request proto expected HTTP/1.1, but got %q", req.Proto)
- }
- if req.Host != "server.example.com" {
- t.Errorf("request Host expected example.com, but got %v", req.Host)
- }
- var expectedHeader = map[string]string{
- "Connection": "Upgrade",
- "Upgrade": "websocket",
- "Sec-Websocket-Key": config.handshakeData["key"],
- "Sec-Websocket-Origin": config.Origin.String(),
- "Sec-Websocket-Protocol": "chat, superchat",
- "Sec-Websocket-Version": fmt.Sprintf("%d", ProtocolVersionHybi08),
- }
- for k, v := range expectedHeader {
- if req.Header.Get(k) != v {
- t.Errorf(fmt.Sprintf("%s expected %q but got %q", k, v, req.Header.Get(k)))
- }
- }
-}
-
-func TestHybiServerHandshake(t *testing.T) {
- config := new(Config)
- handshaker := &hybiServerHandshaker{Config: config}
- br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
-Host: server.example.com
-Upgrade: websocket
-Connection: Upgrade
-Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
-Origin: http://example.com
-Sec-WebSocket-Protocol: chat, superchat
-Sec-WebSocket-Version: 13
-
-`))
- req, err := http.ReadRequest(br)
- if err != nil {
- t.Fatal("request", err)
- }
- code, err := handshaker.ReadHandshake(br, req)
- if err != nil {
- t.Errorf("handshake failed: %v", err)
- }
- if code != http.StatusSwitchingProtocols {
- t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code)
- }
- b := bytes.NewBuffer([]byte{})
- bw := bufio.NewWriter(b)
-
- config.Protocol = []string{"chat"}
-
- err = handshaker.AcceptHandshake(bw)
- if err != nil {
- t.Errorf("handshake response failed: %v", err)
- }
- expectedResponse := strings.Join([]string{
- "HTTP/1.1 101 Switching Protocols",
- "Upgrade: websocket",
- "Connection: Upgrade",
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
- "Sec-WebSocket-Protocol: chat",
- "", ""}, "\r\n")
-
- if b.String() != expectedResponse {
- t.Errorf("handshake expected %q but got %q", expectedResponse, b.String())
- }
-}
-
-func TestHybiServerHandshakeHybi08(t *testing.T) {
- config := new(Config)
- handshaker := &hybiServerHandshaker{Config: config}
- br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
-Host: server.example.com
-Upgrade: websocket
-Connection: Upgrade
-Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
-Sec-WebSocket-Origin: http://example.com
-Sec-WebSocket-Protocol: chat, superchat
-Sec-WebSocket-Version: 8
-
-`))
- req, err := http.ReadRequest(br)
- if err != nil {
- t.Fatal("request", err)
- }
- code, err := handshaker.ReadHandshake(br, req)
- if err != nil {
- t.Errorf("handshake failed: %v", err)
- }
- if code != http.StatusSwitchingProtocols {
- t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code)
- }
- b := bytes.NewBuffer([]byte{})
- bw := bufio.NewWriter(b)
-
- config.Protocol = []string{"chat"}
-
- err = handshaker.AcceptHandshake(bw)
- if err != nil {
- t.Errorf("handshake response failed: %v", err)
- }
- expectedResponse := strings.Join([]string{
- "HTTP/1.1 101 Switching Protocols",
- "Upgrade: websocket",
- "Connection: Upgrade",
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
- "Sec-WebSocket-Protocol: chat",
- "", ""}, "\r\n")
-
- if b.String() != expectedResponse {
- t.Errorf("handshake expected %q but got %q", expectedResponse, b.String())
- }
-}
-
-func TestHybiServerHandshakeHybiBadVersion(t *testing.T) {
- config := new(Config)
- handshaker := &hybiServerHandshaker{Config: config}
- br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
-Host: server.example.com
-Upgrade: websocket
-Connection: Upgrade
-Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
-Sec-WebSocket-Origin: http://example.com
-Sec-WebSocket-Protocol: chat, superchat
-Sec-WebSocket-Version: 9
-
-`))
- req, err := http.ReadRequest(br)
- if err != nil {
- t.Fatal("request", err)
- }
- code, err := handshaker.ReadHandshake(br, req)
- if err != ErrBadWebSocketVersion {
- t.Errorf("handshake expected err %q but got %q", ErrBadWebSocketVersion, err)
- }
- if code != http.StatusBadRequest {
- t.Errorf("status expected %q but got %q", http.StatusBadRequest, code)
- }
-}
-
-func testHybiFrame(t *testing.T, testHeader, testPayload, testMaskedPayload []byte, frameHeader *hybiFrameHeader) {
- b := bytes.NewBuffer([]byte{})
- frameWriterFactory := &hybiFrameWriterFactory{bufio.NewWriter(b), false}
- w, _ := frameWriterFactory.NewFrameWriter(TextFrame)
- w.(*hybiFrameWriter).header = frameHeader
- _, err := w.Write(testPayload)
- w.Close()
- if err != nil {
- t.Errorf("Write error %q", err)
- }
- var expectedFrame []byte
- expectedFrame = append(expectedFrame, testHeader...)
- expectedFrame = append(expectedFrame, testMaskedPayload...)
- if !bytes.Equal(expectedFrame, b.Bytes()) {
- t.Errorf("frame expected %q got %q", expectedFrame, b.Bytes())
- }
- frameReaderFactory := &hybiFrameReaderFactory{bufio.NewReader(b)}
- r, err := frameReaderFactory.NewFrameReader()
- if err != nil {
- t.Errorf("Read error %q", err)
- }
- if header := r.HeaderReader(); header == nil {
- t.Errorf("no header")
- } else {
- actualHeader := make([]byte, r.Len())
- n, err := header.Read(actualHeader)
- if err != nil {
- t.Errorf("Read header error %q", err)
- } else {
- if n < len(testHeader) {
- t.Errorf("header too short %q got %q", testHeader, actualHeader[:n])
- }
- if !bytes.Equal(testHeader, actualHeader[:n]) {
- t.Errorf("header expected %q got %q", testHeader, actualHeader[:n])
- }
- }
- }
- if trailer := r.TrailerReader(); trailer != nil {
- t.Errorf("unexpected trailer %q", trailer)
- }
- frame := r.(*hybiFrameReader)
- if frameHeader.Fin != frame.header.Fin ||
- frameHeader.OpCode != frame.header.OpCode ||
- len(testPayload) != int(frame.header.Length) {
- t.Errorf("mismatch %v (%d) vs %v", frameHeader, len(testPayload), frame)
- }
- payload := make([]byte, len(testPayload))
- _, err = r.Read(payload)
- if err != nil {
- t.Errorf("read %v", err)
- }
- if !bytes.Equal(testPayload, payload) {
- t.Errorf("payload %q vs %q", testPayload, payload)
- }
-}
-
-func TestHybiShortTextFrame(t *testing.T) {
- frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame}
- payload := []byte("hello")
- testHybiFrame(t, []byte{0x81, 0x05}, payload, payload, frameHeader)
-
- payload = make([]byte, 125)
- testHybiFrame(t, []byte{0x81, 125}, payload, payload, frameHeader)
-}
-
-func TestHybiShortMaskedTextFrame(t *testing.T) {
- frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame,
- MaskingKey: []byte{0xcc, 0x55, 0x80, 0x20}}
- payload := []byte("hello")
- maskedPayload := []byte{0xa4, 0x30, 0xec, 0x4c, 0xa3}
- header := []byte{0x81, 0x85}
- header = append(header, frameHeader.MaskingKey...)
- testHybiFrame(t, header, payload, maskedPayload, frameHeader)
-}
-
-func TestHybiShortBinaryFrame(t *testing.T) {
- frameHeader := &hybiFrameHeader{Fin: true, OpCode: BinaryFrame}
- payload := []byte("hello")
- testHybiFrame(t, []byte{0x82, 0x05}, payload, payload, frameHeader)
-
- payload = make([]byte, 125)
- testHybiFrame(t, []byte{0x82, 125}, payload, payload, frameHeader)
-}
-
-func TestHybiControlFrame(t *testing.T) {
- frameHeader := &hybiFrameHeader{Fin: true, OpCode: PingFrame}
- payload := []byte("hello")
- testHybiFrame(t, []byte{0x89, 0x05}, payload, payload, frameHeader)
-
- frameHeader = &hybiFrameHeader{Fin: true, OpCode: PongFrame}
- testHybiFrame(t, []byte{0x8A, 0x05}, payload, payload, frameHeader)
-
- frameHeader = &hybiFrameHeader{Fin: true, OpCode: CloseFrame}
- payload = []byte{0x03, 0xe8} // 1000
- testHybiFrame(t, []byte{0x88, 0x02}, payload, payload, frameHeader)
-}
-
-func TestHybiLongFrame(t *testing.T) {
- frameHeader := &hybiFrameHeader{Fin: true, OpCode: TextFrame}
- payload := make([]byte, 126)
- testHybiFrame(t, []byte{0x81, 126, 0x00, 126}, payload, payload, frameHeader)
-
- payload = make([]byte, 65535)
- testHybiFrame(t, []byte{0x81, 126, 0xff, 0xff}, payload, payload, frameHeader)
-
- payload = make([]byte, 65536)
- testHybiFrame(t, []byte{0x81, 127, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00}, payload, payload, frameHeader)
-}
-
-func TestHybiClientRead(t *testing.T) {
- wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o',
- 0x89, 0x05, 'h', 'e', 'l', 'l', 'o', // ping
- 0x81, 0x05, 'w', 'o', 'r', 'l', 'd'}
- br := bufio.NewReader(bytes.NewBuffer(wireData))
- bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
- conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil)
-
- msg := make([]byte, 512)
- n, err := conn.Read(msg)
- if err != nil {
- t.Errorf("read 1st frame, error %q", err)
- }
- if n != 5 {
- t.Errorf("read 1st frame, expect 5, got %d", n)
- }
- if !bytes.Equal(wireData[2:7], msg[:n]) {
- t.Errorf("read 1st frame %v, got %v", wireData[2:7], msg[:n])
- }
- n, err = conn.Read(msg)
- if err != nil {
- t.Errorf("read 2nd frame, error %q", err)
- }
- if n != 5 {
- t.Errorf("read 2nd frame, expect 5, got %d", n)
- }
- if !bytes.Equal(wireData[16:21], msg[:n]) {
- t.Errorf("read 2nd frame %v, got %v", wireData[16:21], msg[:n])
- }
- n, err = conn.Read(msg)
- if err == nil {
- t.Errorf("read not EOF")
- }
- if n != 0 {
- t.Errorf("expect read 0, got %d", n)
- }
-}
-
-func TestHybiShortRead(t *testing.T) {
- wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o',
- 0x89, 0x05, 'h', 'e', 'l', 'l', 'o', // ping
- 0x81, 0x05, 'w', 'o', 'r', 'l', 'd'}
- br := bufio.NewReader(bytes.NewBuffer(wireData))
- bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
- conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil)
-
- step := 0
- pos := 0
- expectedPos := []int{2, 5, 16, 19}
- expectedLen := []int{3, 2, 3, 2}
- for {
- msg := make([]byte, 3)
- n, err := conn.Read(msg)
- if step >= len(expectedPos) {
- if err == nil {
- t.Errorf("read not EOF")
- }
- if n != 0 {
- t.Errorf("expect read 0, got %d", n)
- }
- return
- }
- pos = expectedPos[step]
- endPos := pos + expectedLen[step]
- if err != nil {
- t.Errorf("read from %d, got error %q", pos, err)
- return
- }
- if n != endPos-pos {
- t.Errorf("read from %d, expect %d, got %d", pos, endPos-pos, n)
- }
- if !bytes.Equal(wireData[pos:endPos], msg[:n]) {
- t.Errorf("read from %d, frame %v, got %v", pos, wireData[pos:endPos], msg[:n])
- }
- step++
- }
-}
-
-func TestHybiServerRead(t *testing.T) {
- wireData := []byte{0x81, 0x85, 0xcc, 0x55, 0x80, 0x20,
- 0xa4, 0x30, 0xec, 0x4c, 0xa3, // hello
- 0x89, 0x85, 0xcc, 0x55, 0x80, 0x20,
- 0xa4, 0x30, 0xec, 0x4c, 0xa3, // ping: hello
- 0x81, 0x85, 0xed, 0x83, 0xb4, 0x24,
- 0x9a, 0xec, 0xc6, 0x48, 0x89, // world
- }
- br := bufio.NewReader(bytes.NewBuffer(wireData))
- bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
- conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, new(http.Request))
-
- expected := [][]byte{[]byte("hello"), []byte("world")}
-
- msg := make([]byte, 512)
- n, err := conn.Read(msg)
- if err != nil {
- t.Errorf("read 1st frame, error %q", err)
- }
- if n != 5 {
- t.Errorf("read 1st frame, expect 5, got %d", n)
- }
- if !bytes.Equal(expected[0], msg[:n]) {
- t.Errorf("read 1st frame %q, got %q", expected[0], msg[:n])
- }
-
- n, err = conn.Read(msg)
- if err != nil {
- t.Errorf("read 2nd frame, error %q", err)
- }
- if n != 5 {
- t.Errorf("read 2nd frame, expect 5, got %d", n)
- }
- if !bytes.Equal(expected[1], msg[:n]) {
- t.Errorf("read 2nd frame %q, got %q", expected[1], msg[:n])
- }
-
- n, err = conn.Read(msg)
- if err == nil {
- t.Errorf("read not EOF")
- }
- if n != 0 {
- t.Errorf("expect read 0, got %d", n)
- }
-}
-
-func TestHybiServerReadWithoutMasking(t *testing.T) {
- wireData := []byte{0x81, 0x05, 'h', 'e', 'l', 'l', 'o'}
- br := bufio.NewReader(bytes.NewBuffer(wireData))
- bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
- conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, new(http.Request))
- // server MUST close the connection upon receiving a non-masked frame.
- msg := make([]byte, 512)
- _, err := conn.Read(msg)
- if err != io.EOF {
- t.Errorf("read 1st frame, expect %q, but got %q", io.EOF, err)
- }
-}
-
-func TestHybiClientReadWithMasking(t *testing.T) {
- wireData := []byte{0x81, 0x85, 0xcc, 0x55, 0x80, 0x20,
- 0xa4, 0x30, 0xec, 0x4c, 0xa3, // hello
- }
- br := bufio.NewReader(bytes.NewBuffer(wireData))
- bw := bufio.NewWriter(bytes.NewBuffer([]byte{}))
- conn := newHybiConn(newConfig(t, "/"), bufio.NewReadWriter(br, bw), nil, nil)
-
- // client MUST close the connection upon receiving a masked frame.
- msg := make([]byte, 512)
- _, err := conn.Read(msg)
- if err != io.EOF {
- t.Errorf("read 1st frame, expect %q, but got %q", io.EOF, err)
- }
-}
-
-// Test the hybiServerHandshaker supports firefox implementation and
-// checks Connection request header include (but it's not necessary
-// equal to) "upgrade"
-func TestHybiServerFirefoxHandshake(t *testing.T) {
- config := new(Config)
- handshaker := &hybiServerHandshaker{Config: config}
- br := bufio.NewReader(strings.NewReader(`GET /chat HTTP/1.1
-Host: server.example.com
-Upgrade: websocket
-Connection: keep-alive, upgrade
-Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
-Origin: http://example.com
-Sec-WebSocket-Protocol: chat, superchat
-Sec-WebSocket-Version: 13
-
-`))
- req, err := http.ReadRequest(br)
- if err != nil {
- t.Fatal("request", err)
- }
- code, err := handshaker.ReadHandshake(br, req)
- if err != nil {
- t.Errorf("handshake failed: %v", err)
- }
- if code != http.StatusSwitchingProtocols {
- t.Errorf("status expected %q but got %q", http.StatusSwitchingProtocols, code)
- }
- b := bytes.NewBuffer([]byte{})
- bw := bufio.NewWriter(b)
-
- config.Protocol = []string{"chat"}
-
- err = handshaker.AcceptHandshake(bw)
- if err != nil {
- t.Errorf("handshake response failed: %v", err)
- }
- expectedResponse := strings.Join([]string{
- "HTTP/1.1 101 Switching Protocols",
- "Upgrade: websocket",
- "Connection: Upgrade",
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
- "Sec-WebSocket-Protocol: chat",
- "", ""}, "\r\n")
-
- if b.String() != expectedResponse {
- t.Errorf("handshake expected %q but got %q", expectedResponse, b.String())
- }
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/server.go b/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/server.go
deleted file mode 100644
index 63f48e2..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/server.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bufio"
- "fmt"
- "io"
- "net/http"
-)
-
-func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request) (conn *Conn, err error) {
- config := new(Config)
- var hs serverHandshaker = &hybiServerHandshaker{Config: config}
- code, err := hs.ReadHandshake(buf.Reader, req)
- if err == ErrBadWebSocketVersion {
- fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
- fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion)
- buf.WriteString("\r\n")
- buf.WriteString(err.Error())
- buf.Flush()
- return
- }
- if err != nil {
- hs = &hixie76ServerHandshaker{Config: config}
- code, err = hs.ReadHandshake(buf.Reader, req)
- }
- if err != nil {
- hs = &hixie75ServerHandshaker{Config: config}
- code, err = hs.ReadHandshake(buf.Reader, req)
- }
- if err != nil {
- fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
- buf.WriteString("\r\n")
- buf.WriteString(err.Error())
- buf.Flush()
- return
- }
- config.Protocol = nil
-
- err = hs.AcceptHandshake(buf.Writer)
- if err != nil {
- code = http.StatusBadRequest
- fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
- buf.WriteString("\r\n")
- buf.Flush()
- return
- }
- conn = hs.NewServerConn(buf, rwc, req)
- return
-}
-
-/*
-Handler is an interface to a WebSocket.
-
-A trivial example server:
-
- package main
-
- import (
- "io"
- "net/http"
- "websocket"
- )
-
- // Echo the data received on the WebSocket.
- func EchoServer(ws *websocket.Conn) {
- io.Copy(ws, ws);
- }
-
- func main() {
- http.Handle("/echo", websocket.Handler(EchoServer));
- err := http.ListenAndServe(":12345", nil);
- if err != nil {
- panic("ListenAndServe: " + err.Error())
- }
- }
-*/
-type Handler func(*Conn)
-
-// ServeHTTP implements the http.Handler interface for a Web Socket
-func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- rwc, buf, err := w.(http.Hijacker).Hijack()
- if err != nil {
- panic("Hijack failed: " + err.Error())
- return
- }
- // The server should abort the WebSocket connection if it finds
- // the client did not send a handshake that matches with protocol
- // specification.
- defer rwc.Close()
- conn, err := newServerConn(rwc, buf, req)
- if err != nil {
- return
- }
- if conn == nil {
- panic("unepxected nil conn")
- }
- h(conn)
-}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/websocket.go b/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/websocket.go
deleted file mode 100644
index f7aabc9..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/websocket.go
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package websocket implements a client and server for the WebSocket protocol.
-// The protocol is defined at http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol
-package websocket
-
-import (
- "bufio"
- "crypto/tls"
- "encoding/json"
- "errors"
- "io"
- "io/ioutil"
- "net"
- "net/http"
- "net/url"
- "sync"
- "time"
-)
-
-const (
- ProtocolVersionHixie75 = -75
- ProtocolVersionHixie76 = -76
- ProtocolVersionHybi00 = 0
- ProtocolVersionHybi08 = 8
- ProtocolVersionHybi13 = 13
- ProtocolVersionHybi = ProtocolVersionHybi13
- SupportedProtocolVersion = "13, 8"
-
- ContinuationFrame = 0
- TextFrame = 1
- BinaryFrame = 2
- CloseFrame = 8
- PingFrame = 9
- PongFrame = 10
- UnknownFrame = 255
-)
-
-// WebSocket protocol errors.
-type ProtocolError struct {
- ErrorString string
-}
-
-func (err *ProtocolError) Error() string { return err.ErrorString }
-
-var (
- ErrBadProtocolVersion = &ProtocolError{"bad protocol version"}
- ErrBadScheme = &ProtocolError{"bad scheme"}
- ErrBadStatus = &ProtocolError{"bad status"}
- ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"}
- ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"}
- ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
- ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
- ErrBadWebSocketVersion = &ProtocolError{"missing or bad WebSocket Version"}
- ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"}
- ErrBadFrame = &ProtocolError{"bad frame"}
- ErrBadFrameBoundary = &ProtocolError{"not on frame boundary"}
- ErrNotWebSocket = &ProtocolError{"not websocket protocol"}
- ErrBadRequestMethod = &ProtocolError{"bad method"}
- ErrNotSupported = &ProtocolError{"not supported"}
-)
-
-// Addr is an implementation of net.Addr for WebSocket.
-type Addr struct {
- *url.URL
-}
-
-// Network returns the network type for a WebSocket, "websocket".
-func (addr *Addr) Network() string { return "websocket" }
-
-// Config is a WebSocket configuration
-type Config struct {
- // A WebSocket server address.
- Location *url.URL
-
- // A Websocket client origin.
- Origin *url.URL
-
- // WebSocket subprotocols.
- Protocol []string
-
- // WebSocket protocol version.
- Version int
-
- // TLS config for secure WebSocket (wss).
- TlsConfig *tls.Config
-
- handshakeData map[string]string
-}
-
-// serverHandshaker is an interface to handle WebSocket server side handshake.
-type serverHandshaker interface {
- // ReadHandshake reads handshake request message from client.
- // Returns http response code and error if any.
- ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error)
-
- // AcceptHandshake accepts the client handshake request and sends
- // handshake response back to client.
- AcceptHandshake(buf *bufio.Writer) (err error)
-
- // NewServerConn creates a new WebSocket connection.
- NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn)
-}
-
-// frameReader is an interface to read a WebSocket frame.
-type frameReader interface {
- // Reader is to read payload of the frame.
- io.Reader
-
- // PayloadType returns payload type.
- PayloadType() byte
-
- // HeaderReader returns a reader to read header of the frame.
- HeaderReader() io.Reader
-
- // TrailerReader returns a reader to read trailer of the frame.
- // If it returns nil, there is no trailer in the frame.
- TrailerReader() io.Reader
-
- // Len returns total length of the frame, including header and trailer.
- Len() int
-}
-
-// frameReaderFactory is an interface to creates new frame reader.
-type frameReaderFactory interface {
- NewFrameReader() (r frameReader, err error)
-}
-
-// frameWriter is an interface to write a WebSocket frame.
-type frameWriter interface {
- // Writer is to write playload of the frame.
- io.WriteCloser
-}
-
-// frameWriterFactory is an interface to create new frame writer.
-type frameWriterFactory interface {
- NewFrameWriter(payloadType byte) (w frameWriter, err error)
-}
-
-type frameHandler interface {
- HandleFrame(frame frameReader) (r frameReader, err error)
- WriteClose(status int) (err error)
-}
-
-// Conn represents a WebSocket connection.
-type Conn struct {
- config *Config
- request *http.Request
-
- buf *bufio.ReadWriter
- rwc io.ReadWriteCloser
-
- rio sync.Mutex
- frameReaderFactory
- frameReader
-
- wio sync.Mutex
- frameWriterFactory
-
- frameHandler
- PayloadType byte
- defaultCloseStatus int
-}
-
-// Read implements the io.Reader interface:
-// it reads data of a frame from the WebSocket connection.
-// if msg is not large enough for the frame data, it fills the msg and next Read
-// will read the rest of the frame data.
-// it reads Text frame or Binary frame.
-func (ws *Conn) Read(msg []byte) (n int, err error) {
- ws.rio.Lock()
- defer ws.rio.Unlock()
-again:
- if ws.frameReader == nil {
- frame, err := ws.frameReaderFactory.NewFrameReader()
- if err != nil {
- return 0, err
- }
- ws.frameReader, err = ws.frameHandler.HandleFrame(frame)
- if err != nil {
- return 0, err
- }
- if ws.frameReader == nil {
- goto again
- }
- }
- n, err = ws.frameReader.Read(msg)
- if err == io.EOF {
- if trailer := ws.frameReader.TrailerReader(); trailer != nil {
- io.Copy(ioutil.Discard, trailer)
- }
- ws.frameReader = nil
- goto again
- }
- return n, err
-}
-
-// Write implements the io.Writer interface:
-// it writes data as a frame to the WebSocket connection.
-func (ws *Conn) Write(msg []byte) (n int, err error) {
- ws.wio.Lock()
- defer ws.wio.Unlock()
- w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType)
- if err != nil {
- return 0, err
- }
- n, err = w.Write(msg)
- w.Close()
- if err != nil {
- return n, err
- }
- return n, err
-}
-
-// Close implements the io.Closer interface.
-func (ws *Conn) Close() error {
- err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
- if err != nil {
- return err
- }
- return ws.rwc.Close()
-}
-
-func (ws *Conn) IsClientConn() bool { return ws.request == nil }
-func (ws *Conn) IsServerConn() bool { return ws.request != nil }
-
-// LocalAddr returns the WebSocket Origin for the connection for client, or
-// the WebSocket location for server.
-func (ws *Conn) LocalAddr() net.Addr {
- if ws.IsClientConn() {
- return &Addr{ws.config.Origin}
- }
- return &Addr{ws.config.Location}
-}
-
-// RemoteAddr returns the WebSocket location for the connection for client, or
-// the Websocket Origin for server.
-func (ws *Conn) RemoteAddr() net.Addr {
- if ws.IsClientConn() {
- return &Addr{ws.config.Location}
- }
- return &Addr{ws.config.Origin}
-}
-
-var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn")
-
-// SetDeadline sets the connection's network read & write deadlines.
-func (ws *Conn) SetDeadline(t time.Time) error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetDeadline(t)
- }
- return errSetDeadline
-}
-
-// SetReadDeadline sets the connection's network read deadline.
-func (ws *Conn) SetReadDeadline(t time.Time) error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetReadDeadline(t)
- }
- return errSetDeadline
-}
-
-// SetWriteDeadline sets the connection's network write deadline.
-func (ws *Conn) SetWriteDeadline(t time.Time) error {
- if conn, ok := ws.rwc.(net.Conn); ok {
- return conn.SetWriteDeadline(t)
- }
- return errSetDeadline
-}
-
-// Config returns the WebSocket config.
-func (ws *Conn) Config() *Config { return ws.config }
-
-// Request returns the http request upgraded to the WebSocket.
-// It is nil for client side.
-func (ws *Conn) Request() *http.Request { return ws.request }
-
-// Codec represents a symmetric pair of functions that implement a codec.
-type Codec struct {
- Marshal func(v interface{}) (data []byte, payloadType byte, err error)
- Unmarshal func(data []byte, payloadType byte, v interface{}) (err error)
-}
-
-// Send sends v marshaled by cd.Marshal as single frame to ws.
-func (cd Codec) Send(ws *Conn, v interface{}) (err error) {
- if err != nil {
- return err
- }
- data, payloadType, err := cd.Marshal(v)
- if err != nil {
- return err
- }
- ws.wio.Lock()
- defer ws.wio.Unlock()
- w, err := ws.frameWriterFactory.NewFrameWriter(payloadType)
- _, err = w.Write(data)
- w.Close()
- return err
-}
-
-// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores in v.
-func (cd Codec) Receive(ws *Conn, v interface{}) (err error) {
- ws.rio.Lock()
- defer ws.rio.Unlock()
- if ws.frameReader != nil {
- _, err = io.Copy(ioutil.Discard, ws.frameReader)
- if err != nil {
- return err
- }
- ws.frameReader = nil
- }
-again:
- frame, err := ws.frameReaderFactory.NewFrameReader()
- if err != nil {
- return err
- }
- frame, err = ws.frameHandler.HandleFrame(frame)
- if err != nil {
- return err
- }
- if frame == nil {
- goto again
- }
- payloadType := frame.PayloadType()
- data, err := ioutil.ReadAll(frame)
- if err != nil {
- return err
- }
- return cd.Unmarshal(data, payloadType, v)
-}
-
-func marshal(v interface{}) (msg []byte, payloadType byte, err error) {
- switch data := v.(type) {
- case string:
- return []byte(data), TextFrame, nil
- case []byte:
- return data, BinaryFrame, nil
- }
- return nil, UnknownFrame, ErrNotSupported
-}
-
-func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
- switch data := v.(type) {
- case *string:
- *data = string(msg)
- return nil
- case *[]byte:
- *data = msg
- return nil
- }
- return ErrNotSupported
-}
-
-/*
-Message is a codec to send/receive text/binary data in a frame on WebSocket connection.
-To send/receive text frame, use string type.
-To send/receive binary frame, use []byte type.
-
-Trivial usage:
-
- import "websocket"
-
- // receive text frame
- var message string
- websocket.Message.Receive(ws, &message)
-
- // send text frame
- message = "hello"
- websocket.Message.Send(ws, message)
-
- // receive binary frame
- var data []byte
- websocket.Message.Receive(ws, &data)
-
- // send binary frame
- data = []byte{0, 1, 2}
- websocket.Message.Send(ws, data)
-
-*/
-var Message = Codec{marshal, unmarshal}
-
-func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
- msg, err = json.Marshal(v)
- return msg, TextFrame, err
-}
-
-func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
- return json.Unmarshal(msg, v)
-}
-
-/*
-JSON is a codec to send/receive JSON data in a frame from a WebSocket connection.
-
-Trival usage:
-
- import "websocket"
-
- type T struct {
- Msg string
- Count int
- }
-
- // receive JSON type T
- var data T
- websocket.JSON.Receive(ws, &data)
-
- // send JSON type T
- websocket.JSON.Send(ws, data)
-*/
-var JSON = Codec{jsonMarshal, jsonUnmarshal}
diff --git a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/websocket_test.go b/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/websocket_test.go
deleted file mode 100644
index 27c58a0..0000000
--- a/eBook/examples/chapter_15/code.google.com/p/go.net/websocket/websocket_test.go
+++ /dev/null
@@ -1,274 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package websocket
-
-import (
- "bytes"
- "fmt"
- "io"
- "log"
- "net"
- "net/http"
- "net/http/httptest"
- "net/url"
- "strings"
- "sync"
- "testing"
-)
-
-var serverAddr string
-var once sync.Once
-
-func echoServer(ws *Conn) { io.Copy(ws, ws) }
-
-type Count struct {
- S string
- N int
-}
-
-func countServer(ws *Conn) {
- for {
- var count Count
- err := JSON.Receive(ws, &count)
- if err != nil {
- return
- }
- count.N++
- count.S = strings.Repeat(count.S, count.N)
- err = JSON.Send(ws, count)
- if err != nil {
- return
- }
- }
-}
-
-func startServer() {
- http.Handle("/echo", Handler(echoServer))
- http.Handle("/count", Handler(countServer))
- server := httptest.NewServer(nil)
- serverAddr = server.Listener.Addr().String()
- log.Print("Test WebSocket server listening on ", serverAddr)
-}
-
-func newConfig(t *testing.T, path string) *Config {
- config, _ := NewConfig(fmt.Sprintf("ws://%s%s", serverAddr, path), "http://localhost")
- return config
-}
-
-func TestEcho(t *testing.T) {
- once.Do(startServer)
-
- // websocket.Dial()
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
- conn, err := NewClient(newConfig(t, "/echo"), client)
- if err != nil {
- t.Errorf("WebSocket handshake error: %v", err)
- return
- }
-
- msg := []byte("hello, world\n")
- if _, err := conn.Write(msg); err != nil {
- t.Errorf("Write: %v", err)
- }
- var actual_msg = make([]byte, 512)
- n, err := conn.Read(actual_msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- actual_msg = actual_msg[0:n]
- if !bytes.Equal(msg, actual_msg) {
- t.Errorf("Echo: expected %q got %q", msg, actual_msg)
- }
- conn.Close()
-}
-
-func TestAddr(t *testing.T) {
- once.Do(startServer)
-
- // websocket.Dial()
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
- conn, err := NewClient(newConfig(t, "/echo"), client)
- if err != nil {
- t.Errorf("WebSocket handshake error: %v", err)
- return
- }
-
- ra := conn.RemoteAddr().String()
- if !strings.HasPrefix(ra, "ws://") || !strings.HasSuffix(ra, "/echo") {
- t.Errorf("Bad remote addr: %v", ra)
- }
- la := conn.LocalAddr().String()
- if !strings.HasPrefix(la, "http://") {
- t.Errorf("Bad local addr: %v", la)
- }
- conn.Close()
-}
-
-func TestCount(t *testing.T) {
- once.Do(startServer)
-
- // websocket.Dial()
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
- conn, err := NewClient(newConfig(t, "/count"), client)
- if err != nil {
- t.Errorf("WebSocket handshake error: %v", err)
- return
- }
-
- var count Count
- count.S = "hello"
- if err := JSON.Send(conn, count); err != nil {
- t.Errorf("Write: %v", err)
- }
- if err := JSON.Receive(conn, &count); err != nil {
- t.Errorf("Read: %v", err)
- }
- if count.N != 1 {
- t.Errorf("count: expected %d got %d", 1, count.N)
- }
- if count.S != "hello" {
- t.Errorf("count: expected %q got %q", "hello", count.S)
- }
- if err := JSON.Send(conn, count); err != nil {
- t.Errorf("Write: %v", err)
- }
- if err := JSON.Receive(conn, &count); err != nil {
- t.Errorf("Read: %v", err)
- }
- if count.N != 2 {
- t.Errorf("count: expected %d got %d", 2, count.N)
- }
- if count.S != "hellohello" {
- t.Errorf("count: expected %q got %q", "hellohello", count.S)
- }
- conn.Close()
-}
-
-func TestWithQuery(t *testing.T) {
- once.Do(startServer)
-
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
-
- config := newConfig(t, "/echo")
- config.Location, err = url.ParseRequestURI(fmt.Sprintf("ws://%s/echo?q=v", serverAddr))
- if err != nil {
- t.Fatal("location url", err)
- }
-
- ws, err := NewClient(config, client)
- if err != nil {
- t.Errorf("WebSocket handshake: %v", err)
- return
- }
- ws.Close()
-}
-
-func TestWithProtocol(t *testing.T) {
- once.Do(startServer)
-
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
-
- config := newConfig(t, "/echo")
- config.Protocol = append(config.Protocol, "test")
-
- ws, err := NewClient(config, client)
- if err != nil {
- t.Errorf("WebSocket handshake: %v", err)
- return
- }
- ws.Close()
-}
-
-func TestHTTP(t *testing.T) {
- once.Do(startServer)
-
- // If the client did not send a handshake that matches the protocol
- // specification, the server MUST return an HTTP respose with an
- // appropriate error code (such as 400 Bad Request)
- resp, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr))
- if err != nil {
- t.Errorf("Get: error %#v", err)
- return
- }
- if resp == nil {
- t.Error("Get: resp is null")
- return
- }
- if resp.StatusCode != http.StatusBadRequest {
- t.Errorf("Get: expected %q got %q", http.StatusBadRequest, resp.StatusCode)
- }
-}
-
-func TestTrailingSpaces(t *testing.T) {
- // http://code.google.com/p/go/issues/detail?id=955
- // The last runs of this create keys with trailing spaces that should not be
- // generated by the client.
- once.Do(startServer)
- config := newConfig(t, "/echo")
- for i := 0; i < 30; i++ {
- // body
- ws, err := DialConfig(config)
- if err != nil {
- t.Errorf("Dial #%d failed: %v", i, err)
- break
- }
- ws.Close()
- }
-}
-
-func TestSmallBuffer(t *testing.T) {
- // http://code.google.com/p/go/issues/detail?id=1145
- // Read should be able to handle reading a fragment of a frame.
- once.Do(startServer)
-
- // websocket.Dial()
- client, err := net.Dial("tcp", serverAddr)
- if err != nil {
- t.Fatal("dialing", err)
- }
- conn, err := NewClient(newConfig(t, "/echo"), client)
- if err != nil {
- t.Errorf("WebSocket handshake error: %v", err)
- return
- }
-
- msg := []byte("hello, world\n")
- if _, err := conn.Write(msg); err != nil {
- t.Errorf("Write: %v", err)
- }
- var small_msg = make([]byte, 8)
- n, err := conn.Read(small_msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- if !bytes.Equal(msg[:len(small_msg)], small_msg) {
- t.Errorf("Echo: expected %q got %q", msg[:len(small_msg)], small_msg)
- }
- var second_msg = make([]byte, len(msg))
- n, err = conn.Read(second_msg)
- if err != nil {
- t.Errorf("Read: %v", err)
- }
- second_msg = second_msg[0:n]
- if !bytes.Equal(msg[len(small_msg):], second_msg) {
- t.Errorf("Echo: expected %q got %q", msg[len(small_msg):], second_msg)
- }
- conn.Close()
-}
diff --git a/eBook/examples/chapter_15/dial.go b/eBook/examples/chapter_15/dial.go
deleted file mode 100644
index 29754ab..0000000
--- a/eBook/examples/chapter_15/dial.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// dial.go.go
-package main
-
-import (
- "fmt"
- "net"
- "os"
-)
-
-func main() {
- conn, err:= net.Dial("tcp", "192.0.32.10:80")
- checkConnection(conn, err)
-
- conn, err =net.Dial("udp", "192.0.32.10:80")
- checkConnection(conn, err)
-
- conn, err =net.Dial("tcp", "[2620:0:2d0:200::10]:80")
- checkConnection(conn, err)
-}
-
-func checkConnection(conn net.Conn, err error) {
- if err!= nil {
- fmt.Printf("error %v connecting!")
- os.Exit(1)
- }
-
- fmt.Println("Connection is made with %v", conn)
-
-}
diff --git a/eBook/examples/chapter_15/elaborated_webserver.go b/eBook/examples/chapter_15/elaborated_webserver.go
deleted file mode 100644
index 60c17f2..0000000
--- a/eBook/examples/chapter_15/elaborated_webserver.go
+++ /dev/null
@@ -1,146 +0,0 @@
-//Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-package main
-
-import (
- "bytes"
- "expvar"
- "flag"
- "fmt"
- "net/http"
- "io"
- "log"
- "os"
- "strconv"
-)
-
-// hello world, the web server
-var helloRequests = expvar.NewInt("hello-requests")
-// flags:
-var webroot = flag.String("root", "/home/user", "web root directory")
-// simple flag server
-var booleanflag = flag.Bool("boolean", true, "another flag for testing")
-
-// Simple counter server. POSTing to it will set the value.
-type Counter struct {
- n int
-}
-
-// a channel
-type Chan chan int
-
-func main() {
- flag.Parse()
- http.Handle("/", http.HandlerFunc(Logger))
- http.Handle("/go/hello", http.HandlerFunc(HelloServer))
- // The counter is published as a variable directly.
- ctr := new(Counter)
- expvar.Publish("counter", ctr)
- http.Handle("/counter", ctr)
- // http.Handle("/go/", http.FileServer(http.Dir("/tmp"))) // uses the OS filesystem
- http.Handle("/go/", http.StripPrefix("/go/", http.FileServer(http.Dir(*webroot))))
- http.Handle("/flags", http.HandlerFunc(FlagServer))
- http.Handle("/args", http.HandlerFunc(ArgServer))
- http.Handle("/chan", ChanCreate())
- http.Handle("/date", http.HandlerFunc(DateServer))
- err := http.ListenAndServe(":12345", nil)
- if err != nil {
- log.Panicln("ListenAndServe:", err)
- }
-}
-
-func Logger(w http.ResponseWriter, req *http.Request) {
- log.Print(req.URL.String())
- w.WriteHeader(404)
- w.Write([]byte("oops"))
-}
-
-func HelloServer(w http.ResponseWriter, req *http.Request) {
- helloRequests.Add(1)
- io.WriteString(w, "hello, world!\n")
-}
-
-// This makes Counter satisfy the expvar.Var interface, so we can export
-// it directly.
-func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) }
-
-func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- switch req.Method {
- case "GET": // increment n
- ctr.n++
- case "POST": // set n to posted value
- buf := new(bytes.Buffer)
- io.Copy(buf, req.Body)
- body := buf.String()
- if n, err := strconv.Atoi(body); err != nil {
- fmt.Fprintf(w, "bad POST: %v\nbody: [%v]\n", err, body)
- } else {
- ctr.n = n
- fmt.Fprint(w, "counter reset\n")
- }
- }
- fmt.Fprintf(w, "counter = %d\n", ctr.n)
-}
-
-func FlagServer(w http.ResponseWriter, req *http.Request) {
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- fmt.Fprint(w, "Flags:\n")
- flag.VisitAll(func(f *flag.Flag) {
- if f.Value.String() != f.DefValue {
- fmt.Fprintf(w, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue)
- } else {
- fmt.Fprintf(w, "%s = %s\n", f.Name, f.Value.String())
- }
- })
-}
-
-// simple argument server
-func ArgServer(w http.ResponseWriter, req *http.Request) {
- for _, s := range os.Args {
- fmt.Fprint(w, s, " ")
- }
-}
-
-func ChanCreate() Chan {
- c := make(Chan)
- go func(c Chan) {
- for x := 0; ; x++ {
- c <- x
- }
- }(c)
- return c
-}
-
-func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
- io.WriteString(w, fmt.Sprintf("channel send #%d\n", <-ch))
-}
-
-// exec a program, redirecting output
-func DateServer(rw http.ResponseWriter, req *http.Request) {
- rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
- r, w, err := os.Pipe()
- if err != nil {
- fmt.Fprintf(rw, "pipe: %s\n", err)
- return
- }
-
- p, err := os.StartProcess("/bin/date", []string{"date"}, &os.ProcAttr{Files: []*os.File{nil, w, w}})
- defer r.Close()
- w.Close()
- if err != nil {
- fmt.Fprintf(rw, "fork/exec: %s\n", err)
- return
- }
- defer p.Release()
- io.Copy(rw, r)
- wait, err := p.Wait()
- if err != nil {
- fmt.Fprintf(rw, "wait: %s\n", err)
- return
- }
- if !wait.Exited() {
- fmt.Fprintf(rw, "date: %v\n", wait)
- return
- }
-}
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/hello_world_webserver.go b/eBook/examples/chapter_15/hello_world_webserver.go
deleted file mode 100644
index d2414e8..0000000
--- a/eBook/examples/chapter_15/hello_world_webserver.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// hello_world_webserver.go
-package main
-
-import (
- "fmt"
- "net/http"
- "log"
-)
-
-func HelloServer(w http.ResponseWriter, req *http.Request) {
- fmt.Println("Inside HelloServer handler")
- //fmt.Fprint(w, "Hello, " + req.URL.Path[1:])
- fmt.Fprintf(w, "Hello, %s ", req.URL.Path[1:])
- // io.WriteString(w, "hello, world!\n")
-}
-
-func main() {
- http.HandleFunc("/", HelloServer)
- err := http.ListenAndServe("localhost:8080", nil)
- if err != nil {
- log.Fatal("ListenAndServe: ", err.Error())
- }
- // http.ListenAndServe(":8080", http.HandlerFunc(HelloServer))
-}
diff --git a/eBook/examples/chapter_15/http_fetch.go b/eBook/examples/chapter_15/http_fetch.go
deleted file mode 100644
index 8b66d62..0000000
--- a/eBook/examples/chapter_15/http_fetch.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// httpfetch.go
-package main
-
-import (
- "fmt"
- "net/http"
- "io/ioutil"
- "log"
-)
-
-func main() {
- res, err := http.Get("http://www.google.com")
- CheckError(err)
- data, err := ioutil.ReadAll(res.Body)
- CheckError(err)
- fmt.Printf("Got: %q", string(data))
-}
-
-func CheckError(err error) {
- if err != nil {
- log.Fatalf("Get: %v", err)
- }
-}
diff --git a/eBook/examples/chapter_15/pipeline1.go b/eBook/examples/chapter_15/pipeline1.go
deleted file mode 100644
index 32d74ee..0000000
--- a/eBook/examples/chapter_15/pipeline1.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// pipeline1.go
-package main
-
-import (
- "text/template"
- "os"
-)
-
-func main() {
- t := template.New("template test")
- t = template.Must(t.Parse("This is just static text. \n{{\"This is pipeline data - because it is evaluated within the double braces.\"}} {{`So is this, but within reverse quotes.`}}\n"))
- t.Execute(os.Stdout, nil)
-}
-/*
-This is just static text.
-This is pipeline data - because it is evaluated within the double braces. So is this, but within reverse quotes.
-*/
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/poll_url.go b/eBook/examples/chapter_15/poll_url.go
deleted file mode 100644
index 2efe5f2..0000000
--- a/eBook/examples/chapter_15/poll_url.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// poll_url.go
-package main
-
-import (
- "fmt"
- "net/http"
-)
-
-var urls = []string{
- "http://www.google.com/",
- "http://golang.org/",
- "http://blog.golang.org/",
-}
-
-func main() {
- // Execute an HTTP HEAD request for all url's
- // and returns the HTTP status string or an error string.
- for _, url := range urls {
- resp, err := http.Head(url)
- if err != nil {
- fmt.Println("Error", url, err)
- }
- fmt.Print(url, ": ", resp.Status)
- }
-}
-/* Output:
-http://www.google.com/ : 302 Found
-http://golang.org/ : 200 OK
-http://blog.golang.org/ : 200 OK
-*/
diff --git a/eBook/examples/chapter_15/predefined_functions.go b/eBook/examples/chapter_15/predefined_functions.go
deleted file mode 100644
index ec8962e..0000000
--- a/eBook/examples/chapter_15/predefined_functions.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// predefined_functions.go
-package main
-
-import (
- "os"
- "text/template"
-)
-
-func main() {
- t := template.New("test")
- t = template.Must(t.Parse("{{with $x := `hello`}}{{printf `%s %s` $x `Mary`}}{{end}}!\n"))
- t.Execute(os.Stdout, nil)
-}
-// hello Mary!
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/robust_webserver.go b/eBook/examples/chapter_15/robust_webserver.go
deleted file mode 100644
index 07501fe..0000000
--- a/eBook/examples/chapter_15/robust_webserver.go
+++ /dev/null
@@ -1,57 +0,0 @@
-// robust_webserver.go
-package main
-
-import (
- "net/http"
- "io"
- "log"
-)
-
-const form = ``
-
-type HandleFnc func(http.ResponseWriter,*http.Request)
-
-/* handle a simple get request */
-func SimpleServer(w http.ResponseWriter, request *http.Request) {
- io.WriteString(w, "hello, world
")
-}
-
-/* handle a form, both the GET which displays the form
- and the POST which processes it.*/
-func FormServer(w http.ResponseWriter, request *http.Request) {
- w.Header().Set("Content-Type", "text/html")
- switch request.Method {
- case "GET":
- /* display the form to the user */
- io.WriteString(w, form );
- case "POST":
- /* handle the form data, note that ParseForm must
- be called before we can extract form data*/
- //request.ParseForm();
- //io.WriteString(w, request.Form["in"][0])
- io.WriteString(w, request.FormValue("in"))
- }
-}
-
-func main() {
- http.HandleFunc("/test1", logPanics(SimpleServer))
- http.HandleFunc("/test2", logPanics(FormServer))
- if err := http.ListenAndServe(":8088", nil); err != nil {
- panic(err)
- }
-}
-
-func logPanics(function HandleFnc) HandleFnc {
- return func(writer http.ResponseWriter, request *http.Request) {
- defer func() {
- if x := recover(); x != nil {
- log.Printf("[%v] caught panic: %v", request.RemoteAddr, x)
- }
- }()
- function(writer, request)
- }
-}
-
diff --git a/eBook/examples/chapter_15/rpc_client.go b/eBook/examples/chapter_15/rpc_client.go
deleted file mode 100644
index 3d0ea60..0000000
--- a/eBook/examples/chapter_15/rpc_client.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// rpc_client.go
-// if the server is not started:
-// can't get the server to start, so client stops immediately with error:
-// 2011/08/01 16:08:05 Error dialing:dial tcp :1234:
-// The requested address is not valid in its context.
-// with serverAddress = localhost:
-// 2011/08/01 16:09:23 Error dialing:dial tcp 127.0.0.1:1234:
-// No connection could be made because the target machine actively refused it.
-package main
-
-import (
- "fmt"
- "log"
- "net/rpc"
- "./rpc_objects"
-)
-
-const serverAddress = "localhost"
-
-func main() {
- client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
- if err != nil {
- log.Fatal("Error dialing:", err)
- }
- // Synchronous call
- args := &rpc_objects.Args{7, 8}
- var reply int
- err = client.Call("Args.Multiply", args, &reply)
- if err != nil {
- log.Fatal("Args error:", err)
- }
- fmt.Printf("Args: %d * %d = %d", args.N, args.M, reply)
-}
-/* Output:
-Starting Process E:/Go/GoBoek/code_examples/chapter_14/rpc_client.exe ...
-
-Args: 7 * 8 = 56
-End Process exit status 0
-*/
diff --git a/eBook/examples/chapter_15/rpc_objects.go b/eBook/examples/chapter_15/rpc_objects.go
deleted file mode 100644
index 76def53..0000000
--- a/eBook/examples/chapter_15/rpc_objects.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// rpc_objects.go
-package rpc_objects
-
-import "net"
-
-type Args struct {
- N, M int
-}
-
-func (t *Args) Multiply(args *Args, reply *int) net.Error {
- *reply = args.N * args.M
- return nil
-}
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/rpc_server.go b/eBook/examples/chapter_15/rpc_server.go
deleted file mode 100644
index 7184b48..0000000
--- a/eBook/examples/chapter_15/rpc_server.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// rpc_server.go
-// after client-exits the server shows the message:
-// 1:1234: The specified network name is no longer available.
-// 2011/08/01 16:19:04 rpc: rpc: server cannot decode request: WSARecv tcp 127.0.0.
-package main
-
-import (
- "net/http"
- "log"
- "net"
- "net/rpc"
- "time"
- "./rpc_objects"
-)
-
-func main() {
- calc := new(rpc_objects.Args)
- rpc.Register(calc)
- rpc.HandleHTTP()
- listener, e := net.Listen("tcp", "localhost:1234")
- if e != nil {
- log.Fatal("Starting RPC-server -listen error:", e)
- }
- go http.Serve(listener, nil)
- time.Sleep(1000e9)
-}
-/* Output:
-Starting Process E:/Go/GoBoek/code_examples/chapter_14/rpc_server.exe ...
-
-** after 5 s: **
-End Process exit status 0
-*/
diff --git a/eBook/examples/chapter_15/server.go b/eBook/examples/chapter_15/server.go
deleted file mode 100644
index f7938bb..0000000
--- a/eBook/examples/chapter_15/server.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package main
-
-import (
- "fmt"
- "net"
-)
-
-func main() {
- fmt.Println("Starting the server ...")
- // create listener:
- listener, err := net.Listen("tcp", "localhost:50000")
- if err != nil {
- fmt.Println("Error listening", err.Error())
- return // terminate program
- }
- // listen and accept connections from clients:
- for {
- conn, err := listener.Accept()
- if err != nil {
- fmt.Println("Error accepting", err.Error())
- return // terminate program
- }
- go doServerStuff(conn)
- }
-}
-
-func doServerStuff(conn net.Conn) {
- for {
- buf := make([]byte, 512)
- _, err := conn.Read(buf)
- if err != nil {
- fmt.Println("Error reading", err.Error())
- return // terminate program
- }
- fmt.Printf("Received data: %v", string(buf))
- }
-}
diff --git a/eBook/examples/chapter_15/simple_tcp_server.go b/eBook/examples/chapter_15/simple_tcp_server.go
deleted file mode 100644
index 79b6c22..0000000
--- a/eBook/examples/chapter_15/simple_tcp_server.go
+++ /dev/null
@@ -1,86 +0,0 @@
-/**
- * Simple multi-thread/multi-core TCP server.
- *
-*/
-package main
-
-import (
- "flag"
- "net"
- "fmt"
- "syscall"
-)
-
-const maxRead = 25
-
-func main() {
- flag.Parse()
- if flag.NArg() != 2 {
- panic("usage: host port")
- }
- hostAndPort := fmt.Sprintf("%s:%s", flag.Arg(0), flag.Arg(1))
- listener := initServer(hostAndPort)
- for {
- conn, err := listener.Accept()
- checkError(err, "Accept: ")
- go connectionHandler(conn)
- }
-}
-
-func initServer(hostAndPort string) *net.TCPListener {
- serverAddr, err := net.ResolveTCPAddr("tcp", hostAndPort)
- checkError(err, "Resolving address:port failed: `" + hostAndPort + "'")
- listener, err := net.ListenTCP("tcp", serverAddr)
- checkError(err, "ListenTCP: ")
- println("Listening to: ", listener.Addr().String())
- return listener
-}
-
-func connectionHandler(conn net.Conn) {
- connFrom := conn.RemoteAddr().String()
- println("Connection from: ", connFrom)
- sayHello(conn)
- for {
- var ibuf []byte = make([]byte, maxRead + 1)
- length, err := conn.Read(ibuf[0:maxRead])
- ibuf[maxRead] = 0 // to prevent overflow
- switch err {
- case nil:
- handleMsg(length, err, ibuf)
- case syscall.EAGAIN: // try again
- continue
- default:
- goto DISCONNECT
- }
- }
-
-DISCONNECT:
- err := conn.Close()
- println("Closed connection: ", connFrom)
- checkError(err, "Close: ")
-}
-
-func sayHello(to net.Conn) {
- obuf := []byte{'L', 'e', 't', '\'', 's', ' ', 'G', 'O', '!', '\n'}
- wrote, err := to.Write(obuf)
- checkError(err, "Write: wrote " + string(wrote) + " bytes.")
-}
-
-func handleMsg(length int, err error, msg []byte) {
- if length > 0 {
- print("<", length, ":")
- for i := 0; ; i++ {
- if msg[i] == 0 {
- break
- }
- fmt.Printf("%c", msg[i])
- }
- print(">")
- }
-}
-
-func checkError(error error, info string) {
- if error != nil {
- panic("ERROR: " + info + " " + error.Error()) // terminate program
- }
-}
diff --git a/eBook/examples/chapter_15/simple_webserver.go b/eBook/examples/chapter_15/simple_webserver.go
deleted file mode 100644
index bf17349..0000000
--- a/eBook/examples/chapter_15/simple_webserver.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// simple_webserver.go
-package main
-
-import (
- "net/http"
- "io"
-)
-
-const form = ``
-
-/* handle a simple get request */
-func SimpleServer(w http.ResponseWriter, request *http.Request) {
- io.WriteString(w, "hello, world
")
-}
-
-/* handle a form, both the GET which displays the form
- and the POST which processes it.*/
-func FormServer(w http.ResponseWriter, request *http.Request) {
- w.Header().Set("Content-Type", "text/html")
- switch request.Method {
- case "GET":
- /* display the form to the user */
- io.WriteString(w, form );
- case "POST":
- /* handle the form data, note that ParseForm must
- be called before we can extract form data*/
- //request.ParseForm();
- //io.WriteString(w, request.Form["in"][0])
- io.WriteString(w, request.FormValue("in"))
- }
-}
-
-func main() {
- http.HandleFunc("/test1", SimpleServer)
- http.HandleFunc("/test2", FormServer)
- if err := http.ListenAndServe(":8088", nil); err != nil {
- panic(err)
- }
-}
diff --git a/eBook/examples/chapter_15/smtp.go b/eBook/examples/chapter_15/smtp.go
deleted file mode 100644
index 58338c1..0000000
--- a/eBook/examples/chapter_15/smtp.go
+++ /dev/null
@@ -1,30 +0,0 @@
-// smtp.go
-package main
-
-import (
- "bytes"
- "log"
- "net/smtp"
-)
-
-func main() {
- // Connect to the remote SMTP server.
- client, err := smtp.Dial("mail.example.com:25")
- if err != nil {
- log.Fatal(err)
- }
- // Set the sender and recipient.
- client.Mail("sender@example.org")
- client.Rcpt("recipient@example.net")
- // Send the email body.
- wc, err := client.Data()
- if err != nil {
- log.Fatal(err)
- }
- defer wc.Close()
- buf := bytes.NewBufferString("This is the email body.")
- if _, err = buf.WriteTo(wc); err != nil {
- log.Fatal(err)
- }
-}
-
diff --git a/eBook/examples/chapter_15/smtp_auth.go b/eBook/examples/chapter_15/smtp_auth.go
deleted file mode 100644
index 91a298b..0000000
--- a/eBook/examples/chapter_15/smtp_auth.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// smtp_auth.go
-package main
-
-import (
- "log"
- "net/smtp"
-)
-
-func main() {
- // Set up authentication information.
- auth := smtp.PlainAuth(
- "",
- "user@example.com",
- "password",
- "mail.example.com",
- )
- // Connect to the server, authenticate, set the sender and recipient,
- // and send the email all in one step.
- err := smtp.SendMail(
- "mail.example.com:25",
- auth,
- "sender@example.org",
- []string{"recipient@example.net"},
- []byte("This is the email body."),
- )
- if err != nil {
- log.Fatal(err)
- }
-}
diff --git a/eBook/examples/chapter_15/socket.go b/eBook/examples/chapter_15/socket.go
deleted file mode 100644
index f5a4d3d..0000000
--- a/eBook/examples/chapter_15/socket.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// socket.go
-package main
-
-import (
- "fmt"
- "net"
- "io"
-)
-
-func main() {
- var (
- host = "www.apache.org"
- port = "80"
- remote = host + ":" + port
- msg string = "GET / \n"
- data = make([]uint8, 4096)
- read = true
- count = 0
- )
- // create the socket
- con, err := net.Dial("tcp", remote)
- // send our message. an HTTP GET request in this case
- io.WriteString(con, msg)
- // read the response from the webserver
- for read {
- count, err = con.Read(data)
- read = (err == nil)
- fmt.Printf(string(data[0:count]))
- }
-
- con.Close()
-}
diff --git a/eBook/examples/chapter_15/template_field.go b/eBook/examples/chapter_15/template_field.go
deleted file mode 100644
index cac2ada..0000000
--- a/eBook/examples/chapter_15/template_field.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// template_field.go
-package main
-
-import (
- "fmt"
- "os"
- "text/template"
-)
-
-type Person struct {
- Name string
- nonExportedAgeField string
-}
-
-func main() {
- t := template.New("hello")
- t, _ = t.Parse("hello {{.Name}}!")
- p := Person{Name:"Mary", nonExportedAgeField: "31"}
- if err := t.Execute(os.Stdout, p); err != nil {
- fmt.Println("There was an error:", err.Error())
- }
-}
-// Output: hello Mary!
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/template_ifelse.go b/eBook/examples/chapter_15/template_ifelse.go
deleted file mode 100644
index cd47316..0000000
--- a/eBook/examples/chapter_15/template_ifelse.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// template_ifelse.go
-package main
-
-import (
- "os"
- "text/template"
-)
-
-func main() {
- tEmpty := template.New("template test")
- tEmpty = template.Must(tEmpty.Parse("Empty pipeline if demo: {{if ``}} Will not print. {{end}}\n")) //empty pipeline following if
- tEmpty.Execute(os.Stdout, nil)
-
- tWithValue := template.New("template test")
- tWithValue = template.Must(tWithValue.Parse("Non empty pipeline if demo: {{if `anything`}} Will print. {{end}}\n")) //non empty pipeline following if condition
- tWithValue.Execute(os.Stdout, nil)
-
- tIfElse := template.New("template test")
- tIfElse = template.Must(tIfElse.Parse("if-else demo: {{if `anything`}} Print IF part. {{else}} Print ELSE part.{{end}}\n")) //non empty pipeline following if condition
- tIfElse.Execute(os.Stdout, nil)
-}
-/* Output:
-Empty pipeline if demo:
-Non empty pipeline if demo: Will print.
-if-else demo: Print IF part.
-*/
diff --git a/eBook/examples/chapter_15/template_validation.go b/eBook/examples/chapter_15/template_validation.go
deleted file mode 100644
index 0969dfb..0000000
--- a/eBook/examples/chapter_15/template_validation.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// template_validation.go
-package main
-
-import (
- "text/template"
- "fmt"
-)
-
-func main() {
- tOk := template.New("ok")
- //a valid template, so no panic with Must:
- template.Must(tOk.Parse("/* and a comment */ some static text: {{ .Name }}"))
- fmt.Println("The first one parsed OK.")
- fmt.Println("The next one ought to fail.")
- tErr := template.New("error_template")
- template.Must(tErr.Parse(" some static text {{ .Name }"))
-}
-/* Output:
-The first one parsed OK.
-The next one ought to fail.
-panic: template: error_template:1: unexpected "}" in command
-*/
diff --git a/eBook/examples/chapter_15/template_variables.go b/eBook/examples/chapter_15/template_variables.go
deleted file mode 100644
index 0e4f5ef..0000000
--- a/eBook/examples/chapter_15/template_variables.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// template_variables.go
-package main
-
-import (
- "os"
- "text/template"
-)
-
-func main() {
- t := template.New("test")
- t = template.Must(t.Parse("{{with $3 := `hello`}}{{$3}}{{end}}!\n"))
- t.Execute(os.Stdout, nil)
-
- t = template.Must(t.Parse("{{with $x3 := `hola`}}{{$x3}}{{end}}!\n"))
- t.Execute(os.Stdout, nil)
-
- t = template.Must(t.Parse("{{with $x_1 := `hey`}}{{$x_1}} {{.}} {{$x_1}}{{end}}!\n"))
- t.Execute(os.Stdout, nil)
-}
-/* Output:
-hello!
-hola!
-hey hey hey!
-*/
diff --git a/eBook/examples/chapter_15/template_with_end.go b/eBook/examples/chapter_15/template_with_end.go
deleted file mode 100644
index 21fc9f4..0000000
--- a/eBook/examples/chapter_15/template_with_end.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// template_with_end.go
-package main
-
-import (
- "os"
- "text/template"
-)
-
-func main() {
- t := template.New("test")
- t, _ = t.Parse("{{with `hello`}}{{.}}{{end}}!\n")
- t.Execute(os.Stdout, nil)
-
- t, _ = t.Parse("{{with `hello`}}{{.}} {{with `Mary`}}{{.}}{{end}}{{end}}!\n")
- t.Execute(os.Stdout, nil)
-}
-/* Output:
-hello!
-hello Mary!
-*/
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/twitter_status.go b/eBook/examples/chapter_15/twitter_status.go
deleted file mode 100644
index 3157ea6..0000000
--- a/eBook/examples/chapter_15/twitter_status.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// twitter_status.go
-package main
-
-import (
- "net/http"
- "fmt"
- "encoding/xml"
- "io/ioutil"
-)
-/* these structs will house the unmarshalled response.
- they should be hierarchically shaped like the XML
- but can omit irrelevant data. */
-type Status struct {
- Text string
-}
-
-type User struct {
- XMLName xml.Name
- Status Status
-}
-// var user User
-
-func main() {
- // perform an HTTP request for the twitter status of user: Googland
- resp, _ := http.Get("http://twitter.com/users/Googland.xml")
- // initialize the structure of the XML response
- user := User{xml.Name{"", "user"}, Status{""}}
- // unmarshal the XML into our structures
- defer resp.Body.Close()
- if body, err := ioutil.ReadAll(resp.Body); err != nil {
- fmt.Printf("error: %s", err.Error())
- } else {
- fmt.Printf("%s ---", body)
- xml.Unmarshal(body, &user)
- }
- fmt.Printf("name: %s ", user.XMLName)
- fmt.Printf("status: %s", user.Status.Text)
-}
-/* Output:
-status: Robot cars invade California, on orders from Google: Google has been testing self-driving cars ... http://bit.ly/cbtpUN http://retwt.me/97p
-After Go1: no output: name: { user} status:
-*/
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/websocket_client.go b/eBook/examples/chapter_15/websocket_client.go
deleted file mode 100644
index 6f2aad3..0000000
--- a/eBook/examples/chapter_15/websocket_client.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// websocket_client.go
-package main
-
-import (
- "fmt"
- "time"
- "code.google.com/p/go.net/websocket"
-)
-
-func main() {
- ws, err := websocket.Dial("ws://localhost:12345/websocket", "",
- "http://localhost/")
- if err != nil {
- panic("Dial: " + err.Error())
- }
- go readFromServer(ws)
- time.Sleep(5e9)
- ws.Close()
-}
-
-func readFromServer(ws *websocket.Conn) {
- buf := make([]byte, 1000)
- for {
- if _, err := ws.Read(buf); err != nil {
- fmt.Printf("%s\n", err.Error())
- break
- }
- }
-}
diff --git a/eBook/examples/chapter_15/websocket_server.go b/eBook/examples/chapter_15/websocket_server.go
deleted file mode 100644
index a191420..0000000
--- a/eBook/examples/chapter_15/websocket_server.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// websocket_server.go
-package main
-
-import (
- "fmt"
- "net/http"
- "code.google.com/p/go.net/websocket"
-)
-
-func server(ws *websocket.Conn) {
- fmt.Printf("new connection\n")
- buf := make([]byte, 100)
- for {
- if _, err := ws.Read(buf); err != nil {
- fmt.Printf("%s", err.Error())
- break
- }
- }
- fmt.Printf(" => closing connection\n")
- ws.Close()
-}
-
-func main() {
- http.Handle("/websocket", websocket.Handler(server))
- err := http.ListenAndServe(":12345", nil)
- if err != nil {
- panic("ListenAndServe: " + err.Error())
- }
-}
diff --git a/eBook/examples/chapter_15/wiki/ANewPage.txt b/eBook/examples/chapter_15/wiki/ANewPage.txt
deleted file mode 100644
index e994fea..0000000
--- a/eBook/examples/chapter_15/wiki/ANewPage.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Testing input of new page!
-Go Go Go !
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/wiki/TestPage.txt b/eBook/examples/chapter_15/wiki/TestPage.txt
deleted file mode 100644
index 0963b99..0000000
--- a/eBook/examples/chapter_15/wiki/TestPage.txt
+++ /dev/null
@@ -1 +0,0 @@
-This is a sample Page.
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/wiki/edit.html b/eBook/examples/chapter_15/wiki/edit.html
deleted file mode 100644
index 34e314a..0000000
--- a/eBook/examples/chapter_15/wiki/edit.html
+++ /dev/null
@@ -1,6 +0,0 @@
-Editing {{.Title |html}}
-
-
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/wiki/page.txt b/eBook/examples/chapter_15/wiki/page.txt
deleted file mode 100644
index 810b9b7..0000000
--- a/eBook/examples/chapter_15/wiki/page.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Hello Go - World !!!
-This works great.
diff --git a/eBook/examples/chapter_15/wiki/page1.txt b/eBook/examples/chapter_15/wiki/page1.txt
deleted file mode 100644
index eedd24f..0000000
--- a/eBook/examples/chapter_15/wiki/page1.txt
+++ /dev/null
@@ -1 +0,0 @@
-This is a test!!
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/wiki/page5.txt b/eBook/examples/chapter_15/wiki/page5.txt
deleted file mode 100644
index 22298c7..0000000
--- a/eBook/examples/chapter_15/wiki/page5.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Page5 is hereby started.
-This is a first addition.
-2nd addition.
\ No newline at end of file
diff --git a/eBook/examples/chapter_15/wiki/view.html b/eBook/examples/chapter_15/wiki/view.html
deleted file mode 100644
index 0233915..0000000
--- a/eBook/examples/chapter_15/wiki/view.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{{.Title |html}}
-
-[edit]
-
-{{printf "%s" .Body |html}}
diff --git a/eBook/examples/chapter_15/wiki/wiki.go b/eBook/examples/chapter_15/wiki/wiki.go
deleted file mode 100644
index ee7a76c..0000000
--- a/eBook/examples/chapter_15/wiki/wiki.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package main
-
-import (
- "io/ioutil"
- "log"
- "net/http"
- "regexp"
- "text/template"
-)
-
-const lenPath = len("/view/")
-
-var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
-var templates = make(map[string]*template.Template)
-var err error
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func init() {
- for _, tmpl := range []string{"edit", "view"} {
- templates[tmpl] = template.Must(template.ParseFiles(tmpl + ".html"))
- }
-}
-
-func main() {
- http.HandleFunc("/view/", makeHandler(viewHandler))
- http.HandleFunc("/edit/", makeHandler(editHandler))
- http.HandleFunc("/save/", makeHandler(saveHandler))
- err := http.ListenAndServe("localhost:8080", nil)
- if err != nil {
- log.Fatal("ListenAndServe: ", err.Error())
- }
-}
-
-func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- if !titleValidator.MatchString(title) {
- http.NotFound(w, r)
- return
- }
- fn(w, r, title)
- }
-}
-
-func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
- p, err := load(title)
- if err != nil { // page not found
- http.Redirect(w, r, "/edit/"+title, http.StatusFound)
- return
- }
- renderTemplate(w, "view", p)
-}
-
-func editHandler(w http.ResponseWriter, r *http.Request, title string) {
- p, err := load(title)
- if err != nil {
- p = &Page{Title: title}
- }
- renderTemplate(w, "edit", p)
-}
-
-func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
- body := r.FormValue("body")
- p := &Page{Title: title, Body: []byte(body)}
- err := p.save()
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- http.Redirect(w, r, "/view/"+title, http.StatusFound)
-}
-
-func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
- err := templates[tmpl].Execute(w, p)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
-}
-
-func (p *Page) save() error {
- filename := p.Title + ".txt"
- // file created with read-write permissions for the current user only
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func load(title string) (*Page, error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
diff --git a/eBook/examples/chapter_15/wiki/wiki_part1.go b/eBook/examples/chapter_15/wiki/wiki_part1.go
deleted file mode 100644
index aec8c38..0000000
--- a/eBook/examples/chapter_15/wiki/wiki_part1.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package main
-
-import (
- "fmt"
- "io/ioutil"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func load(title string) (*Page, error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
-
-func main() {
- p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")}
- p1.save()
- p2, _ := load("TestPage")
- fmt.Println(string(p2.Body))
-}
diff --git a/eBook/examples/chapter_15/wiki/wiki_part2.go b/eBook/examples/chapter_15/wiki/wiki_part2.go
deleted file mode 100644
index a0445ba..0000000
--- a/eBook/examples/chapter_15/wiki/wiki_part2.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package main
-
-import (
- "fmt"
- "net/http"
- "io/ioutil"
-)
-
-type Page struct {
- Title string
- Body []byte
-}
-
-func (p *Page) save() error {
- filename := p.Title + ".txt"
- return ioutil.WriteFile(filename, p.Body, 0600)
-}
-
-func load(title string) (*Page, error) {
- filename := title + ".txt"
- body, err := ioutil.ReadFile(filename)
- if err != nil {
- return nil, err
- }
- return &Page{Title: title, Body: body}, nil
-}
-
-const lenPath = len("/view/")
-
-func viewHandler(w http.ResponseWriter, r *http.Request) {
- title := r.URL.Path[lenPath:]
- p, _ := load(title)
- fmt.Fprintf(w, "%s
%s
", p.Title, p.Body)
-}
-
-func main() {
- http.HandleFunc("/view/", viewHandler)
- http.ListenAndServe(":8080", nil)
-}
diff --git a/eBook/examples/chapter_5/booleans.go b/eBook/examples/chapter_5/booleans.go
new file mode 100644
index 0000000..bcf145f
--- /dev/null
+++ b/eBook/examples/chapter_5/booleans.go
@@ -0,0 +1,12 @@
+package main
+
+import "fmt"
+
+func main() {
+ bool1 := true
+ if bool1 {
+ fmt.Printf("The value is true\n")
+ } else {
+ fmt.Printf("The value is false\n")
+ }
+}
diff --git a/eBook/examples/chapter_5/for1.go b/eBook/examples/chapter_5/for1.go
new file mode 100644
index 0000000..79f958a
--- /dev/null
+++ b/eBook/examples/chapter_5/for1.go
@@ -0,0 +1,9 @@
+package main
+
+import "fmt"
+
+func main() {
+ for i := 0; i < 5; i++ {
+ fmt.Printf("This is the %d iteration\n", i)
+ }
+}
diff --git a/eBook/examples/chapter_5/for2.go b/eBook/examples/chapter_5/for2.go
new file mode 100644
index 0000000..bf9b294
--- /dev/null
+++ b/eBook/examples/chapter_5/for2.go
@@ -0,0 +1,12 @@
+package main
+
+import "fmt"
+
+func main() {
+ var i int = 5
+
+ for i >= 0 {
+ i = i - 1
+ fmt.Printf("The variable i is now: %d\n", i)
+ }
+}
diff --git a/eBook/examples/chapter_5/for3.go b/eBook/examples/chapter_5/for3.go
new file mode 100644
index 0000000..62bd74b
--- /dev/null
+++ b/eBook/examples/chapter_5/for3.go
@@ -0,0 +1,15 @@
+package main
+
+import "fmt"
+
+func main() {
+ var i int = 5
+
+ for {
+ i = i - 1
+ fmt.Printf("The variable i is now: %d\n", i)
+ if i < 0 {
+ break
+ }
+ }
+}
diff --git a/eBook/examples/chapter_5/for4.go b/eBook/examples/chapter_5/for4.go
new file mode 100644
index 0000000..cb16d54
--- /dev/null
+++ b/eBook/examples/chapter_5/for4.go
@@ -0,0 +1,13 @@
+package main
+
+func main() {
+ for i:=0; i<3; i++ {
+ for j:=0; j<10; j++ {
+ if j>5 {
+ break
+ }
+ print(j)
+ }
+ print(" ")
+ }
+}
\ No newline at end of file
diff --git a/eBook/examples/chapter_5/for5.go b/eBook/examples/chapter_5/for5.go
new file mode 100644
index 0000000..6e1135e
--- /dev/null
+++ b/eBook/examples/chapter_5/for5.go
@@ -0,0 +1,11 @@
+package main
+
+func main() {
+ for i := 0; i < 10; i++ {
+ if i == 5 {
+ continue
+ }
+ print(i)
+ print(" ")
+ }
+}
diff --git a/eBook/examples/chapter_5/for6.go b/eBook/examples/chapter_5/for6.go
new file mode 100644
index 0000000..81a96d8
--- /dev/null
+++ b/eBook/examples/chapter_5/for6.go
@@ -0,0 +1,17 @@
+package main
+
+import "fmt"
+
+func main() {
+
+LABEL1:
+ for i := 0; i <= 5; i++ {
+ for j := 0; j <= 5; j++ {
+ if j == 4 {
+ continue LABEL1
+ }
+ fmt.Printf("i is: %d, and j is: %d\n", i, j)
+ }
+ }
+
+}
diff --git a/eBook/examples/chapter_5/for_string.go b/eBook/examples/chapter_5/for_string.go
new file mode 100644
index 0000000..7b18921
--- /dev/null
+++ b/eBook/examples/chapter_5/for_string.go
@@ -0,0 +1,57 @@
+// for_string.go
+package main
+
+import "fmt"
+
+func main() {
+ str := "Go is a beautiful language!"
+ fmt.Printf("The length of str is: %d\n", len(str))
+ for ix :=0; ix < len(str); ix++ {
+ fmt.Printf("Character on position %d is: %c \n", ix, str[ix])
+ }
+ str2 := "日本語"
+ fmt.Printf("The length of str2 is: %d\n", len(str2))
+ for ix :=0; ix < len(str2); ix++ {
+ fmt.Printf("Character on position %d is: %c \n", ix, str2[ix])
+ }
+}
+/* Output:
+The length of str is: 27
+Character on position 0 is: G
+Character on position 1 is: o
+Character on position 2 is:
+Character on position 3 is: i
+Character on position 4 is: s
+Character on position 5 is:
+Character on position 6 is: a
+Character on position 7 is:
+Character on position 8 is: b
+Character on position 9 is: e
+Character on position 10 is: a
+Character on position 11 is: u
+Character on position 12 is: t
+Character on position 13 is: i
+Character on position 14 is: f
+Character on position 15 is: u
+Character on position 16 is: l
+Character on position 17 is:
+Character on position 18 is: l
+Character on position 19 is: a
+Character on position 20 is: n
+Character on position 21 is: g
+Character on position 22 is: u
+Character on position 23 is: a
+Character on position 24 is: g
+Character on position 25 is: e
+Character on position 26 is: !
+The length of str2 is: 9
+Character on position 0 is: æ
+Character on position 1 is:
+Character on position 2 is: ¥
+Character on position 3 is: æ
+Character on position 4 is:
+Character on position 5 is: ¬
+Character on position 6 is: è
+Character on position 7 is: ª
+Character on position 8 is:
+*/
\ No newline at end of file
diff --git a/eBook/examples/chapter_5/goto.go b/eBook/examples/chapter_5/goto.go
new file mode 100644
index 0000000..e61b47c
--- /dev/null
+++ b/eBook/examples/chapter_5/goto.go
@@ -0,0 +1,12 @@
+package main
+
+func main() {
+ i:=0
+ HERE:
+ print(i)
+ i++
+ if i==5 {
+ return
+ }
+ goto HERE
+}
\ No newline at end of file
diff --git a/eBook/examples/chapter_5/goto2.go b/eBook/examples/chapter_5/goto2.go
new file mode 100644
index 0000000..705b9a9
--- /dev/null
+++ b/eBook/examples/chapter_5/goto2.go
@@ -0,0 +1,13 @@
+// compile error goto2.go:8: goto TARGET jumps over declaration of b at goto2.go:8
+package main
+
+import "fmt"
+
+func main() {
+ a := 1
+ goto TARGET // compile error
+ b := 9
+ TARGET:
+ b += a
+ fmt.Printf("a is %v *** b is %v", a, b)
+}
\ No newline at end of file
diff --git a/eBook/examples/chapter_5/ifelse.go b/eBook/examples/chapter_5/ifelse.go
new file mode 100644
index 0000000..0b8dc61
--- /dev/null
+++ b/eBook/examples/chapter_5/ifelse.go
@@ -0,0 +1,22 @@
+package main
+
+import "fmt"
+
+func main() {
+ var first int = 10
+ var cond int
+
+ if first <= 0 {
+ fmt.Printf("first is less than or equal to 0\n")
+ } else if first > 0 && first < 5 {
+ fmt.Printf("first is between 0 and 5\n")
+ } else {
+ fmt.Printf("first is 5 or greater\n")
+ }
+
+ if cond = 5; cond > 10 {
+ fmt.Printf("cond is greater than 10\n")
+ } else {
+ fmt.Printf("cond is not greater than 10\n")
+ }
+}
diff --git a/eBook/examples/chapter_5/range_string.go b/eBook/examples/chapter_5/range_string.go
new file mode 100644
index 0000000..f5bdc2e
--- /dev/null
+++ b/eBook/examples/chapter_5/range_string.go
@@ -0,0 +1,80 @@
+package main
+
+import "fmt"
+
+func main() {
+ str := "Go is a beautiful language!"
+ fmt.Printf("The length of str is: %d\n", len(str))
+ for pos, char := range str {
+ fmt.Printf("Character on position %d is: %c \n", pos, char)
+ }
+ fmt.Println()
+ str2 := "Chinese: 日本語"
+ fmt.Printf("The length of str2 is: %d\n", len(str2))
+ for pos, char := range str2 {
+ fmt.Printf("character %c starts at byte position %d\n", char, pos)
+ }
+ fmt.Println()
+ fmt.Println("index int(rune) rune char bytes")
+ for index, rune := range str2 {
+ fmt.Printf("%-2d %d %U '%c' % X\n", index, rune, rune, rune, []byte(string(rune)))
+ }
+}
+/* Output:
+The length of str is: 27
+Character on position 0 is: G
+Character on position 1 is: o
+Character on position 2 is:
+Character on position 3 is: i
+Character on position 4 is: s
+Character on position 5 is:
+Character on position 6 is: a
+Character on position 7 is:
+Character on position 8 is: b
+Character on position 9 is: e
+Character on position 10 is: a
+Character on position 11 is: u
+Character on position 12 is: t
+Character on position 13 is: i
+Character on position 14 is: f
+Character on position 15 is: u
+Character on position 16 is: l
+Character on position 17 is:
+Character on position 18 is: l
+Character on position 19 is: a
+Character on position 20 is: n
+Character on position 21 is: g
+Character on position 22 is: u
+Character on position 23 is: a
+Character on position 24 is: g
+Character on position 25 is: e
+Character on position 26 is: !
+
+The length of str2 is: 18
+character C starts at byte position 0
+character h starts at byte position 1
+character i starts at byte position 2
+character n starts at byte position 3
+character e starts at byte position 4
+character s starts at byte position 5
+character e starts at byte position 6
+character : starts at byte position 7
+character starts at byte position 8
+character 日 starts at byte position 9
+character 本 starts at byte position 12
+character 語 starts at byte position 15
+
+index int(rune) rune char bytes
+0 67 U+0043 'C' 43
+1 104 U+0068 'h' 68
+2 105 U+0069 'i' 69
+3 110 U+006E 'n' 6E
+4 101 U+0065 'e' 65
+5 115 U+0073 's' 73
+6 101 U+0065 'e' 65
+7 58 U+003A ':' 3A
+8 32 U+0020 ' ' 20
+9 26085 U+65E5 '日' E6 97 A5
+12 26412 U+672C '本' E6 9C AC
+15 35486 U+8A9E '語' E8 AA 9E
+*/
diff --git a/eBook/examples/chapter_5/string_conversion2.go b/eBook/examples/chapter_5/string_conversion2.go
new file mode 100644
index 0000000..4add5eb
--- /dev/null
+++ b/eBook/examples/chapter_5/string_conversion2.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+ "fmt"
+ "strconv"
+)
+
+func main() {
+ var orig string = "ABC"
+ // var an int
+ var newS string
+ // var err error
+
+ fmt.Printf("The size of ints is: %d\n", strconv.IntSize)
+ // anInt, err = strconv.Atoi(origStr)
+ an, err := strconv.Atoi(orig)
+ if err != nil {
+ fmt.Printf("orig %s is not an integer - exiting with error\n", orig)
+ return
+ }
+ fmt.Printf("The integer is %d\n", an)
+ an = an + 5
+ newS = strconv.Itoa(an)
+ fmt.Printf("The new string is: %s\n", newS)
+}
diff --git a/eBook/examples/chapter_5/switch1.go b/eBook/examples/chapter_5/switch1.go
new file mode 100644
index 0000000..a108596
--- /dev/null
+++ b/eBook/examples/chapter_5/switch1.go
@@ -0,0 +1,16 @@
+package main
+
+import "fmt"
+
+func main() {
+ var num1 int = 100
+
+ switch num1 {
+ case 98, 99:
+ fmt.Println("It's equal to 98")
+ case 100:
+ fmt.Println("It's equal to 100")
+ default:
+ fmt.Println("It's not equal to 98 or 100")
+ }
+}
diff --git a/eBook/examples/chapter_5/switch2.go b/eBook/examples/chapter_5/switch2.go
new file mode 100644
index 0000000..4f0afe8
--- /dev/null
+++ b/eBook/examples/chapter_5/switch2.go
@@ -0,0 +1,16 @@
+package main
+
+import "fmt"
+
+func main() {
+ var num1 int = 7
+
+ switch {
+ case num1 < 0:
+ fmt.Println("Number is negative")
+ case num1 > 0 && num1 < 10:
+ fmt.Println("Number is between 0 and 10")
+ default:
+ fmt.Println("Number is 10 or greater")
+ }
+}
diff --git a/eBook/exercises/chapter_5/bitwise_complement.go b/eBook/exercises/chapter_5/bitwise_complement.go
new file mode 100644
index 0000000..c2c2c56
--- /dev/null
+++ b/eBook/exercises/chapter_5/bitwise_complement.go
@@ -0,0 +1,22 @@
+package main
+
+import "fmt"
+
+func main() {
+ for i:=0; i <= 10; i ++ {
+ fmt.Printf("the complement of %b is: %b\n", i, ^i)
+ }
+}
+/* Output:
+the complement of 0 is: -1
+the complement of 1 is: -10
+the complement of 10 is: -11
+the complement of 11 is: -100
+the complement of 100 is: -101
+the complement of 101 is: -110
+the complement of 110 is: -111
+the complement of 111 is: -1000
+the complement of 1000 is: -1001
+the complement of 1001 is: -1010
+the complement of 1010 is: -1011
+*/
\ No newline at end of file
diff --git a/eBook/exercises/chapter_5/fizzbuzz.go b/eBook/exercises/chapter_5/fizzbuzz.go
new file mode 100644
index 0000000..8b30374
--- /dev/null
+++ b/eBook/exercises/chapter_5/fizzbuzz.go
@@ -0,0 +1,24 @@
+package main
+
+import "fmt"
+
+const (
+ FIZZ=3
+ BUZZ=5
+ FIZZBUZZ=15
+)
+
+func main() {
+ for i:=0; i <= 100; i++ {
+ switch {
+ case i%FIZZBUZZ==0:
+ fmt.Println("FizzBuzz")
+ case i%FIZZ==0:
+ fmt.Println("Fizz")
+ case i%BUZZ==0:
+ fmt.Println("Buzz")
+ default:
+ fmt.Println(i)
+ }
+ }
+}
\ No newline at end of file
diff --git a/eBook/exercises/chapter_5/for_character.go b/eBook/exercises/chapter_5/for_character.go
new file mode 100644
index 0000000..98979a4
--- /dev/null
+++ b/eBook/exercises/chapter_5/for_character.go
@@ -0,0 +1,17 @@
+package main
+
+func main() {
+ // 1 - use 2 nested for loops
+ for i:=1; i <= 25; i++ {
+ for j:=1; j <=i; j++ {
+ print("G")
+ }
+ println()
+ }
+ // 2 - use only one for loop and string concatenation
+ str := "G"
+ for i:=1; i <= 25; i++ {
+ println(str)
+ str += "G"
+ }
+}
\ No newline at end of file
diff --git a/eBook/exercises/chapter_5/for_loop.go b/eBook/exercises/chapter_5/for_loop.go
new file mode 100644
index 0000000..b7eeb95
--- /dev/null
+++ b/eBook/exercises/chapter_5/for_loop.go
@@ -0,0 +1,16 @@
+package main
+
+import "fmt"
+
+func main() {
+ // 1:
+ for i:=0; i < 15; i++ {
+ fmt.Printf("The counter is at %d\n", i)
+ }
+ // 2:
+ i := 0
+START:
+ fmt.Printf("The counter is at %d\n", i)
+ i++
+ if i < 15 { goto START }
+}
\ No newline at end of file
diff --git a/eBook/exercises/chapter_5/i_undefined.go b/eBook/exercises/chapter_5/i_undefined.go
new file mode 100644
index 0000000..d4b47e9
--- /dev/null
+++ b/eBook/exercises/chapter_5/i_undefined.go
@@ -0,0 +1,14 @@
+// i_undefined.go
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ var i int
+ for i=0; i<10; i++ {
+ fmt.Printf("%v\n", i)
+ }
+ fmt.Printf("%v\n", i) //<-- compile error: undefined i
+}
diff --git a/eBook/exercises/chapter_5/multiple_for.go b/eBook/exercises/chapter_5/multiple_for.go
new file mode 100644
index 0000000..2e7f3d9
--- /dev/null
+++ b/eBook/exercises/chapter_5/multiple_for.go
@@ -0,0 +1,17 @@
+// multiple_for.go
+package main
+
+import "fmt"
+
+func main() {
+ //multiple initialization; a consolidated bool expression with && and ||; multiple ‘incrementation’
+ for i, j, s := 0, 5, "a"; i < 3 && j < 100 && s != "aaaaa"; i, j, s = i+1,
+ j+1, s + "a" {
+ fmt.Println("Value of i, j, s:", i, j, s)
+ }
+}
+/* Output:
+Value of i, j, s: 0 5 a
+Value of i, j, s: 1 6 aa
+Value of i, j, s: 2 7 aaa
+*/
\ No newline at end of file
diff --git a/eBook/exercises/chapter_5/rectangle_stars.go b/eBook/exercises/chapter_5/rectangle_stars.go
new file mode 100644
index 0000000..bb5def0
--- /dev/null
+++ b/eBook/exercises/chapter_5/rectangle_stars.go
@@ -0,0 +1,26 @@
+// rectangle_stars.go
+package main
+
+import "fmt"
+
+func main() {
+ w, h := 20, 10
+ for y := 0; y < h; y++ {
+ for x := 0; x < w; x++ {
+ fmt.Print("*")
+ }
+ fmt.Println()
+ }
+}
+/* Output:
+********************
+********************
+********************
+********************
+********************
+********************
+********************
+********************
+********************
+********************
+*/
diff --git a/eBook/exercises/chapter_5/season.go b/eBook/exercises/chapter_5/season.go
new file mode 100644
index 0000000..1a21bed
--- /dev/null
+++ b/eBook/exercises/chapter_5/season.go
@@ -0,0 +1,17 @@
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Printf(Season(3))
+}
+
+func Season(month int) string {
+ switch month {
+ case 12,1,2: return "Winter"
+ case 3,4,5: return "Spring"
+ case 6,7,8: return "Summer"
+ case 9,10,11: return "Autumn"
+ }
+ return "Season unknown"
+}
\ No newline at end of file