pax_global_header00006660000000000000000000000064126446437240014526gustar00rootroot0000000000000052 comment=4fd4a9fed55e5bdee4a89d6406c2eabe38b60300 golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/000077500000000000000000000000001264464372400204405ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/.gitattributes000066400000000000000000000005311264464372400233320ustar00rootroot00000000000000# Treat all files in this repo as binary, with no git magic updating # line endings. Windows users contributing to Go will need to use a # modern version of git and editors capable of LF line endings. # # We'll prevent accidental CRLF line endings from entering the repo # via the git-review gofmt checks. # # See golang.org/issue/9281 * -text golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/.gitignore000066400000000000000000000001241264464372400224250ustar00rootroot00000000000000# Add no patterns to .hgignore except for files generated by the build. last-change golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/AUTHORS000066400000000000000000000002551264464372400215120ustar00rootroot00000000000000# 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. golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/CONTRIBUTING.md000066400000000000000000000020071264464372400226700ustar00rootroot00000000000000# Contributing to Go Go is an open source project. It is the work of hundreds of contributors. We appreciate your help! ## Filing issues When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: 1. What version of Go are you using (`go version`)? 2. What operating system and processor architecture are you using? 3. What did you do? 4. What did you expect to see? 5. What did you see instead? General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. The gophers there will answer or ask you to file an issue if you've tripped over a bug. ## Contributing code Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) before sending patches. **We do not accept GitHub pull requests** (we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review). Unless otherwise noted, the Go source files are distributed under the BSD-style license found in the LICENSE file. golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/CONTRIBUTORS000066400000000000000000000002521264464372400223170ustar00rootroot00000000000000# 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. golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/LICENSE000066400000000000000000000027071264464372400214530ustar00rootroot00000000000000Copyright (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. golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/PATENTS000066400000000000000000000024271264464372400215060ustar00rootroot00000000000000Additional IP Rights Grant (Patents) "This implementation" means the copyrightable works distributed by Google as part of the Go project. Google hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, transfer and otherwise run, modify and propagate the contents of this implementation of Go, where such license applies only to those patent claims, both currently owned or controlled by Google and acquired in the future, licensable by Google that are necessarily infringed by this implementation of Go. This grant does not include claims that would be infringed only as a consequence of further modification of this implementation. If you or your agent or exclusive licensee institute or order or agree to the institution of patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that this implementation of Go or any code incorporated within this implementation of Go constitutes direct or contributory patent infringement, or inducement of patent infringement, then any patent rights granted to you under this License for this implementation of Go shall terminate as of the date such litigation is filed. golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/README000066400000000000000000000002171264464372400213200ustar00rootroot00000000000000This repository holds supplementary Go networking libraries. To submit changes to this repository, see http://golang.org/doc/contribute.html. golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/codereview.cfg000066400000000000000000000000251264464372400232520ustar00rootroot00000000000000issuerepo: golang/go golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/context/000077500000000000000000000000001264464372400221245ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/context/context.go000066400000000000000000000334611264464372400241460ustar00rootroot00000000000000// Copyright 2014 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 context defines the Context type, which carries deadlines, // cancelation signals, and other request-scoped values across API boundaries // and between processes. // // Incoming requests to a server should create a Context, and outgoing calls to // servers should accept a Context. The chain of function calls between must // propagate the Context, optionally replacing it with a modified copy created // using WithDeadline, WithTimeout, WithCancel, or WithValue. // // Programs that use Contexts should follow these rules to keep interfaces // consistent across packages and enable static analysis tools to check context // propagation: // // Do not store Contexts inside a struct type; instead, pass a Context // explicitly to each function that needs it. The Context should be the first // parameter, typically named ctx: // // func DoSomething(ctx context.Context, arg Arg) error { // // ... use ctx ... // } // // Do not pass a nil Context, even if a function permits it. Pass context.TODO // if you are unsure about which Context to use. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. // // The same Context may be passed to functions running in different goroutines; // Contexts are safe for simultaneous use by multiple goroutines. // // See http://blog.golang.org/context for example code for a server that uses // Contexts. package context // import "golang.org/x/net/context" import ( "errors" "fmt" "sync" "time" ) // A Context carries a deadline, a cancelation signal, and other values across // API boundaries. // // Context's methods may be called by multiple goroutines simultaneously. type Context interface { // Deadline returns the time when work done on behalf of this context // should be canceled. Deadline returns ok==false when no deadline is // set. Successive calls to Deadline return the same results. Deadline() (deadline time.Time, ok bool) // Done returns a channel that's closed when work done on behalf of this // context should be canceled. Done may return nil if this context can // never be canceled. Successive calls to Done return the same value. // // WithCancel arranges for Done to be closed when cancel is called; // WithDeadline arranges for Done to be closed when the deadline // expires; WithTimeout arranges for Done to be closed when the timeout // elapses. // // Done is provided for use in select statements: // // // Stream generates values with DoSomething and sends them to out // // until DoSomething returns an error or ctx.Done is closed. // func Stream(ctx context.Context, out <-chan Value) error { // for { // v, err := DoSomething(ctx) // if err != nil { // return err // } // select { // case <-ctx.Done(): // return ctx.Err() // case out <- v: // } // } // } // // See http://blog.golang.org/pipelines for more examples of how to use // a Done channel for cancelation. Done() <-chan struct{} // Err returns a non-nil error value after Done is closed. Err returns // Canceled if the context was canceled or DeadlineExceeded if the // context's deadline passed. No other values for Err are defined. // After Done is closed, successive calls to Err return the same value. Err() error // Value returns the value associated with this context for key, or nil // if no value is associated with key. Successive calls to Value with // the same key returns the same result. // // Use context values only for request-scoped data that transits // processes and API boundaries, not for passing optional parameters to // functions. // // A key identifies a specific value in a Context. Functions that wish // to store values in Context typically allocate a key in a global // variable then use that key as the argument to context.WithValue and // Context.Value. A key can be any type that supports equality; // packages should define keys as an unexported type to avoid // collisions. // // Packages that define a Context key should provide type-safe accessors // for the values stores using that key: // // // Package user defines a User type that's stored in Contexts. // package user // // import "golang.org/x/net/context" // // // User is the type of value stored in the Contexts. // type User struct {...} // // // key is an unexported type for keys defined in this package. // // This prevents collisions with keys defined in other packages. // type key int // // // userKey is the key for user.User values in Contexts. It is // // unexported; clients use user.NewContext and user.FromContext // // instead of using this key directly. // var userKey key = 0 // // // NewContext returns a new Context that carries value u. // func NewContext(ctx context.Context, u *User) context.Context { // return context.WithValue(ctx, userKey, u) // } // // // FromContext returns the User value stored in ctx, if any. // func FromContext(ctx context.Context) (*User, bool) { // u, ok := ctx.Value(userKey).(*User) // return u, ok // } Value(key interface{}) interface{} } // Canceled is the error returned by Context.Err when the context is canceled. var Canceled = errors.New("context canceled") // DeadlineExceeded is the error returned by Context.Err when the context's // deadline passes. var DeadlineExceeded = errors.New("context deadline exceeded") // An emptyCtx is never canceled, has no values, and has no deadline. It is not // struct{}, since vars of this type must have distinct addresses. type emptyCtx int func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { return } func (*emptyCtx) Done() <-chan struct{} { return nil } func (*emptyCtx) Err() error { return nil } func (*emptyCtx) Value(key interface{}) interface{} { return nil } func (e *emptyCtx) String() string { switch e { case background: return "context.Background" case todo: return "context.TODO" } return "unknown empty Context" } var ( background = new(emptyCtx) todo = new(emptyCtx) ) // Background returns a non-nil, empty Context. It is never canceled, has no // values, and has no deadline. It is typically used by the main function, // initialization, and tests, and as the top-level Context for incoming // requests. func Background() Context { return background } // TODO returns a non-nil, empty Context. Code should use context.TODO when // it's unclear which Context to use or it is not yet available (because the // surrounding function has not yet been extended to accept a Context // parameter). TODO is recognized by static analysis tools that determine // whether Contexts are propagated correctly in a program. func TODO() Context { return todo } // A CancelFunc tells an operation to abandon its work. // A CancelFunc does not wait for the work to stop. // After the first call, subsequent calls to a CancelFunc do nothing. type CancelFunc func() // WithCancel returns a copy of parent with a new Done channel. The returned // context's Done channel is closed when the returned cancel function is called // or when the parent context's Done channel is closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { c := newCancelCtx(parent) propagateCancel(parent, &c) return &c, func() { c.cancel(true, Canceled) } } // newCancelCtx returns an initialized cancelCtx. func newCancelCtx(parent Context) cancelCtx { return cancelCtx{ Context: parent, done: make(chan struct{}), } } // propagateCancel arranges for child to be canceled when parent is. func propagateCancel(parent Context, child canceler) { if parent.Done() == nil { return // parent is never canceled } if p, ok := parentCancelCtx(parent); ok { p.mu.Lock() if p.err != nil { // parent has already been canceled child.cancel(false, p.err) } else { if p.children == nil { p.children = make(map[canceler]bool) } p.children[child] = true } p.mu.Unlock() } else { go func() { select { case <-parent.Done(): child.cancel(false, parent.Err()) case <-child.Done(): } }() } } // parentCancelCtx follows a chain of parent references until it finds a // *cancelCtx. This function understands how each of the concrete types in this // package represents its parent. func parentCancelCtx(parent Context) (*cancelCtx, bool) { for { switch c := parent.(type) { case *cancelCtx: return c, true case *timerCtx: return &c.cancelCtx, true case *valueCtx: parent = c.Context default: return nil, false } } } // removeChild removes a context from its parent. func removeChild(parent Context, child canceler) { p, ok := parentCancelCtx(parent) if !ok { return } p.mu.Lock() if p.children != nil { delete(p.children, child) } p.mu.Unlock() } // A canceler is a context type that can be canceled directly. The // implementations are *cancelCtx and *timerCtx. type canceler interface { cancel(removeFromParent bool, err error) Done() <-chan struct{} } // A cancelCtx can be canceled. When canceled, it also cancels any children // that implement canceler. type cancelCtx struct { Context done chan struct{} // closed by the first cancel call. mu sync.Mutex children map[canceler]bool // set to nil by the first cancel call err error // set to non-nil by the first cancel call } func (c *cancelCtx) Done() <-chan struct{} { return c.done } func (c *cancelCtx) Err() error { c.mu.Lock() defer c.mu.Unlock() return c.err } func (c *cancelCtx) String() string { return fmt.Sprintf("%v.WithCancel", c.Context) } // cancel closes c.done, cancels each of c's children, and, if // removeFromParent is true, removes c from its parent's children. func (c *cancelCtx) cancel(removeFromParent bool, err error) { if err == nil { panic("context: internal error: missing cancel error") } c.mu.Lock() if c.err != nil { c.mu.Unlock() return // already canceled } c.err = err close(c.done) for child := range c.children { // NOTE: acquiring the child's lock while holding parent's lock. child.cancel(false, err) } c.children = nil c.mu.Unlock() if removeFromParent { removeChild(c.Context, c) } } // WithDeadline returns a copy of the parent context with the deadline adjusted // to be no later than d. If the parent's deadline is already earlier than d, // WithDeadline(parent, d) is semantically equivalent to parent. The returned // context's Done channel is closed when the deadline expires, when the returned // cancel function is called, or when the parent context's Done channel is // closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete. func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { // The current deadline is already sooner than the new one. return WithCancel(parent) } c := &timerCtx{ cancelCtx: newCancelCtx(parent), deadline: deadline, } propagateCancel(parent, c) d := deadline.Sub(time.Now()) if d <= 0 { c.cancel(true, DeadlineExceeded) // deadline has already passed return c, func() { c.cancel(true, Canceled) } } c.mu.Lock() defer c.mu.Unlock() if c.err == nil { c.timer = time.AfterFunc(d, func() { c.cancel(true, DeadlineExceeded) }) } return c, func() { c.cancel(true, Canceled) } } // A timerCtx carries a timer and a deadline. It embeds a cancelCtx to // implement Done and Err. It implements cancel by stopping its timer then // delegating to cancelCtx.cancel. type timerCtx struct { cancelCtx timer *time.Timer // Under cancelCtx.mu. deadline time.Time } func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { return c.deadline, true } func (c *timerCtx) String() string { return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) } func (c *timerCtx) cancel(removeFromParent bool, err error) { c.cancelCtx.cancel(false, err) if removeFromParent { // Remove this timerCtx from its parent cancelCtx's children. removeChild(c.cancelCtx.Context, c) } c.mu.Lock() if c.timer != nil { c.timer.Stop() c.timer = nil } c.mu.Unlock() } // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete: // // func slowOperationWithTimeout(ctx context.Context) (Result, error) { // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) // defer cancel() // releases resources if slowOperation completes before timeout elapses // return slowOperation(ctx) // } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } // WithValue returns a copy of parent in which the value associated with key is // val. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. func WithValue(parent Context, key interface{}, val interface{}) Context { return &valueCtx{parent, key, val} } // A valueCtx carries a key-value pair. It implements Value for that key and // delegates all other calls to the embedded Context. type valueCtx struct { Context key, val interface{} } func (c *valueCtx) String() string { return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) } func (c *valueCtx) Value(key interface{}) interface{} { if c.key == key { return c.val } return c.Context.Value(key) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/context/context_test.go000066400000000000000000000351361264464372400252060ustar00rootroot00000000000000// Copyright 2014 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 context import ( "fmt" "math/rand" "runtime" "strings" "sync" "testing" "time" ) // otherContext is a Context that's not one of the types defined in context.go. // This lets us test code paths that differ based on the underlying type of the // Context. type otherContext struct { Context } func TestBackground(t *testing.T) { c := Background() if c == nil { t.Fatalf("Background returned nil") } select { case x := <-c.Done(): t.Errorf("<-c.Done() == %v want nothing (it should block)", x) default: } if got, want := fmt.Sprint(c), "context.Background"; got != want { t.Errorf("Background().String() = %q want %q", got, want) } } func TestTODO(t *testing.T) { c := TODO() if c == nil { t.Fatalf("TODO returned nil") } select { case x := <-c.Done(): t.Errorf("<-c.Done() == %v want nothing (it should block)", x) default: } if got, want := fmt.Sprint(c), "context.TODO"; got != want { t.Errorf("TODO().String() = %q want %q", got, want) } } func TestWithCancel(t *testing.T) { c1, cancel := WithCancel(Background()) if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want { t.Errorf("c1.String() = %q want %q", got, want) } o := otherContext{c1} c2, _ := WithCancel(o) contexts := []Context{c1, o, c2} for i, c := range contexts { if d := c.Done(); d == nil { t.Errorf("c[%d].Done() == %v want non-nil", i, d) } if e := c.Err(); e != nil { t.Errorf("c[%d].Err() == %v want nil", i, e) } select { case x := <-c.Done(): t.Errorf("<-c.Done() == %v want nothing (it should block)", x) default: } } cancel() time.Sleep(100 * time.Millisecond) // let cancelation propagate for i, c := range contexts { select { case <-c.Done(): default: t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i) } if e := c.Err(); e != Canceled { t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled) } } } func TestParentFinishesChild(t *testing.T) { // Context tree: // parent -> cancelChild // parent -> valueChild -> timerChild parent, cancel := WithCancel(Background()) cancelChild, stop := WithCancel(parent) defer stop() valueChild := WithValue(parent, "key", "value") timerChild, stop := WithTimeout(valueChild, 10000*time.Hour) defer stop() select { case x := <-parent.Done(): t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) case x := <-cancelChild.Done(): t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x) case x := <-timerChild.Done(): t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x) case x := <-valueChild.Done(): t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x) default: } // The parent's children should contain the two cancelable children. pc := parent.(*cancelCtx) cc := cancelChild.(*cancelCtx) tc := timerChild.(*timerCtx) pc.mu.Lock() if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] { t.Errorf("bad linkage: pc.children = %v, want %v and %v", pc.children, cc, tc) } pc.mu.Unlock() if p, ok := parentCancelCtx(cc.Context); !ok || p != pc { t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc) } if p, ok := parentCancelCtx(tc.Context); !ok || p != pc { t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc) } cancel() pc.mu.Lock() if len(pc.children) != 0 { t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children) } pc.mu.Unlock() // parent and children should all be finished. check := func(ctx Context, name string) { select { case <-ctx.Done(): default: t.Errorf("<-%s.Done() blocked, but shouldn't have", name) } if e := ctx.Err(); e != Canceled { t.Errorf("%s.Err() == %v want %v", name, e, Canceled) } } check(parent, "parent") check(cancelChild, "cancelChild") check(valueChild, "valueChild") check(timerChild, "timerChild") // WithCancel should return a canceled context on a canceled parent. precanceledChild := WithValue(parent, "key", "value") select { case <-precanceledChild.Done(): default: t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have") } if e := precanceledChild.Err(); e != Canceled { t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled) } } func TestChildFinishesFirst(t *testing.T) { cancelable, stop := WithCancel(Background()) defer stop() for _, parent := range []Context{Background(), cancelable} { child, cancel := WithCancel(parent) select { case x := <-parent.Done(): t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) case x := <-child.Done(): t.Errorf("<-child.Done() == %v want nothing (it should block)", x) default: } cc := child.(*cancelCtx) pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background() if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) { t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok) } if pcok { pc.mu.Lock() if len(pc.children) != 1 || !pc.children[cc] { t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc) } pc.mu.Unlock() } cancel() if pcok { pc.mu.Lock() if len(pc.children) != 0 { t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children) } pc.mu.Unlock() } // child should be finished. select { case <-child.Done(): default: t.Errorf("<-child.Done() blocked, but shouldn't have") } if e := child.Err(); e != Canceled { t.Errorf("child.Err() == %v want %v", e, Canceled) } // parent should not be finished. select { case x := <-parent.Done(): t.Errorf("<-parent.Done() == %v want nothing (it should block)", x) default: } if e := parent.Err(); e != nil { t.Errorf("parent.Err() == %v want nil", e) } } } func testDeadline(c Context, wait time.Duration, t *testing.T) { select { case <-time.After(wait): t.Fatalf("context should have timed out") case <-c.Done(): } if e := c.Err(); e != DeadlineExceeded { t.Errorf("c.Err() == %v want %v", e, DeadlineExceeded) } } func TestDeadline(t *testing.T) { c, _ := WithDeadline(Background(), time.Now().Add(100*time.Millisecond)) if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { t.Errorf("c.String() = %q want prefix %q", got, prefix) } testDeadline(c, 200*time.Millisecond, t) c, _ = WithDeadline(Background(), time.Now().Add(100*time.Millisecond)) o := otherContext{c} testDeadline(o, 200*time.Millisecond, t) c, _ = WithDeadline(Background(), time.Now().Add(100*time.Millisecond)) o = otherContext{c} c, _ = WithDeadline(o, time.Now().Add(300*time.Millisecond)) testDeadline(c, 200*time.Millisecond, t) } func TestTimeout(t *testing.T) { c, _ := WithTimeout(Background(), 100*time.Millisecond) if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) { t.Errorf("c.String() = %q want prefix %q", got, prefix) } testDeadline(c, 200*time.Millisecond, t) c, _ = WithTimeout(Background(), 100*time.Millisecond) o := otherContext{c} testDeadline(o, 200*time.Millisecond, t) c, _ = WithTimeout(Background(), 100*time.Millisecond) o = otherContext{c} c, _ = WithTimeout(o, 300*time.Millisecond) testDeadline(c, 200*time.Millisecond, t) } func TestCanceledTimeout(t *testing.T) { c, _ := WithTimeout(Background(), 200*time.Millisecond) o := otherContext{c} c, cancel := WithTimeout(o, 400*time.Millisecond) cancel() time.Sleep(100 * time.Millisecond) // let cancelation propagate select { case <-c.Done(): default: t.Errorf("<-c.Done() blocked, but shouldn't have") } if e := c.Err(); e != Canceled { t.Errorf("c.Err() == %v want %v", e, Canceled) } } type key1 int type key2 int var k1 = key1(1) var k2 = key2(1) // same int as k1, different type var k3 = key2(3) // same type as k2, different int func TestValues(t *testing.T) { check := func(c Context, nm, v1, v2, v3 string) { if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 { t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0) } if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 { t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0) } if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 { t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0) } } c0 := Background() check(c0, "c0", "", "", "") c1 := WithValue(Background(), k1, "c1k1") check(c1, "c1", "c1k1", "", "") if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want { t.Errorf("c.String() = %q want %q", got, want) } c2 := WithValue(c1, k2, "c2k2") check(c2, "c2", "c1k1", "c2k2", "") c3 := WithValue(c2, k3, "c3k3") check(c3, "c2", "c1k1", "c2k2", "c3k3") c4 := WithValue(c3, k1, nil) check(c4, "c4", "", "c2k2", "c3k3") o0 := otherContext{Background()} check(o0, "o0", "", "", "") o1 := otherContext{WithValue(Background(), k1, "c1k1")} check(o1, "o1", "c1k1", "", "") o2 := WithValue(o1, k2, "o2k2") check(o2, "o2", "c1k1", "o2k2", "") o3 := otherContext{c4} check(o3, "o3", "", "c2k2", "c3k3") o4 := WithValue(o3, k3, nil) check(o4, "o4", "", "c2k2", "") } func TestAllocs(t *testing.T) { bg := Background() for _, test := range []struct { desc string f func() limit float64 gccgoLimit float64 }{ { desc: "Background()", f: func() { Background() }, limit: 0, gccgoLimit: 0, }, { desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1), f: func() { c := WithValue(bg, k1, nil) c.Value(k1) }, limit: 3, gccgoLimit: 3, }, { desc: "WithTimeout(bg, 15*time.Millisecond)", f: func() { c, _ := WithTimeout(bg, 15*time.Millisecond) <-c.Done() }, limit: 8, gccgoLimit: 15, }, { desc: "WithCancel(bg)", f: func() { c, cancel := WithCancel(bg) cancel() <-c.Done() }, limit: 5, gccgoLimit: 8, }, { desc: "WithTimeout(bg, 100*time.Millisecond)", f: func() { c, cancel := WithTimeout(bg, 100*time.Millisecond) cancel() <-c.Done() }, limit: 8, gccgoLimit: 25, }, } { limit := test.limit if runtime.Compiler == "gccgo" { // gccgo does not yet do escape analysis. // TOOD(iant): Remove this when gccgo does do escape analysis. limit = test.gccgoLimit } if n := testing.AllocsPerRun(100, test.f); n > limit { t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit)) } } } func TestSimultaneousCancels(t *testing.T) { root, cancel := WithCancel(Background()) m := map[Context]CancelFunc{root: cancel} q := []Context{root} // Create a tree of contexts. for len(q) != 0 && len(m) < 100 { parent := q[0] q = q[1:] for i := 0; i < 4; i++ { ctx, cancel := WithCancel(parent) m[ctx] = cancel q = append(q, ctx) } } // Start all the cancels in a random order. var wg sync.WaitGroup wg.Add(len(m)) for _, cancel := range m { go func(cancel CancelFunc) { cancel() wg.Done() }(cancel) } // Wait on all the contexts in a random order. for ctx := range m { select { case <-ctx.Done(): case <-time.After(1 * time.Second): buf := make([]byte, 10<<10) n := runtime.Stack(buf, true) t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n]) } } // Wait for all the cancel functions to return. done := make(chan struct{}) go func() { wg.Wait() close(done) }() select { case <-done: case <-time.After(1 * time.Second): buf := make([]byte, 10<<10) n := runtime.Stack(buf, true) t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n]) } } func TestInterlockedCancels(t *testing.T) { parent, cancelParent := WithCancel(Background()) child, cancelChild := WithCancel(parent) go func() { parent.Done() cancelChild() }() cancelParent() select { case <-child.Done(): case <-time.After(1 * time.Second): buf := make([]byte, 10<<10) n := runtime.Stack(buf, true) t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n]) } } func TestLayersCancel(t *testing.T) { testLayers(t, time.Now().UnixNano(), false) } func TestLayersTimeout(t *testing.T) { testLayers(t, time.Now().UnixNano(), true) } func testLayers(t *testing.T, seed int64, testTimeout bool) { rand.Seed(seed) errorf := func(format string, a ...interface{}) { t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...) } const ( timeout = 200 * time.Millisecond minLayers = 30 ) type value int var ( vals []*value cancels []CancelFunc numTimers int ctx = Background() ) for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ { switch rand.Intn(3) { case 0: v := new(value) ctx = WithValue(ctx, v, v) vals = append(vals, v) case 1: var cancel CancelFunc ctx, cancel = WithCancel(ctx) cancels = append(cancels, cancel) case 2: var cancel CancelFunc ctx, cancel = WithTimeout(ctx, timeout) cancels = append(cancels, cancel) numTimers++ } } checkValues := func(when string) { for _, key := range vals { if val := ctx.Value(key).(*value); key != val { errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key) } } } select { case <-ctx.Done(): errorf("ctx should not be canceled yet") default: } if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) { t.Errorf("ctx.String() = %q want prefix %q", s, prefix) } t.Log(ctx) checkValues("before cancel") if testTimeout { select { case <-ctx.Done(): case <-time.After(timeout + 100*time.Millisecond): errorf("ctx should have timed out") } checkValues("after timeout") } else { cancel := cancels[rand.Intn(len(cancels))] cancel() select { case <-ctx.Done(): default: errorf("ctx should be canceled") } checkValues("after cancel") } } func TestCancelRemoves(t *testing.T) { checkChildren := func(when string, ctx Context, want int) { if got := len(ctx.(*cancelCtx).children); got != want { t.Errorf("%s: context has %d children, want %d", when, got, want) } } ctx, _ := WithCancel(Background()) checkChildren("after creation", ctx, 0) _, cancel := WithCancel(ctx) checkChildren("with WithCancel child ", ctx, 1) cancel() checkChildren("after cancelling WithCancel child", ctx, 0) ctx, _ = WithCancel(Background()) checkChildren("after creation", ctx, 0) _, cancel = WithTimeout(ctx, 60*time.Minute) checkChildren("with WithTimeout child ", ctx, 1) cancel() checkChildren("after cancelling WithTimeout child", ctx, 0) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/context/ctxhttp/000077500000000000000000000000001264464372400236225ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/context/ctxhttp/cancelreq.go000066400000000000000000000006341264464372400261110ustar00rootroot00000000000000// Copyright 2015 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. // +build go1.5 package ctxhttp import "net/http" func canceler(client *http.Client, req *http.Request) func() { // TODO(djd): Respect any existing value of req.Cancel. ch := make(chan struct{}) req.Cancel = ch return func() { close(ch) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/context/ctxhttp/cancelreq_go14.go000066400000000000000000000007231264464372400267420ustar00rootroot00000000000000// Copyright 2015 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. // +build !go1.5 package ctxhttp import "net/http" type requestCanceler interface { CancelRequest(*http.Request) } func canceler(client *http.Client, req *http.Request) func() { rc, ok := client.Transport.(requestCanceler) if !ok { return func() {} } return func() { rc.CancelRequest(req) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/context/ctxhttp/ctxhttp.go000066400000000000000000000061011264464372400256450ustar00rootroot00000000000000// Copyright 2015 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 ctxhttp provides helper functions for performing context-aware HTTP requests. package ctxhttp // import "golang.org/x/net/context/ctxhttp" import ( "io" "net/http" "net/url" "strings" "golang.org/x/net/context" ) // Do sends an HTTP request with the provided http.Client and returns an HTTP response. // If the client is nil, http.DefaultClient is used. // If the context is canceled or times out, ctx.Err() will be returned. func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { if client == nil { client = http.DefaultClient } // Request cancelation changed in Go 1.5, see cancelreq.go and cancelreq_go14.go. cancel := canceler(client, req) type responseAndError struct { resp *http.Response err error } result := make(chan responseAndError, 1) go func() { resp, err := client.Do(req) result <- responseAndError{resp, err} }() var resp *http.Response select { case <-ctx.Done(): cancel() return nil, ctx.Err() case r := <-result: var err error resp, err = r.resp, r.err if err != nil { return resp, err } } c := make(chan struct{}) go func() { select { case <-ctx.Done(): cancel() case <-c: // The response's Body is closed. } }() resp.Body = ¬ifyingReader{resp.Body, c} return resp, nil } // Get issues a GET request via the Do function. func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } return Do(ctx, client, req) } // Head issues a HEAD request via the Do function. func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { req, err := http.NewRequest("HEAD", url, nil) if err != nil { return nil, err } return Do(ctx, client, req) } // Post issues a POST request via the Do function. func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { req, err := http.NewRequest("POST", url, body) if err != nil { return nil, err } req.Header.Set("Content-Type", bodyType) return Do(ctx, client, req) } // PostForm issues a POST request via the Do function. func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) } // notifyingReader is an io.ReadCloser that closes the notify channel after // Close is called or a Read fails on the underlying ReadCloser. type notifyingReader struct { io.ReadCloser notify chan<- struct{} } func (r *notifyingReader) Read(p []byte) (int, error) { n, err := r.ReadCloser.Read(p) if err != nil && r.notify != nil { close(r.notify) r.notify = nil } return n, err } func (r *notifyingReader) Close() error { err := r.ReadCloser.Close() if r.notify != nil { close(r.notify) r.notify = nil } return err } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/context/ctxhttp/ctxhttp_test.go000066400000000000000000000047071264464372400267160ustar00rootroot00000000000000// Copyright 2015 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 ctxhttp import ( "io/ioutil" "net/http" "net/http/httptest" "testing" "time" "golang.org/x/net/context" ) const ( requestDuration = 100 * time.Millisecond requestBody = "ok" ) func TestNoTimeout(t *testing.T) { ctx := context.Background() resp, err := doRequest(ctx) if resp == nil || err != nil { t.Fatalf("error received from client: %v %v", err, resp) } } func TestCancel(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) go func() { time.Sleep(requestDuration / 2) cancel() }() resp, err := doRequest(ctx) if resp != nil || err == nil { t.Fatalf("expected error, didn't get one. resp: %v", resp) } if err != ctx.Err() { t.Fatalf("expected error from context but got: %v", err) } } func TestCancelAfterRequest(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) resp, err := doRequest(ctx) // Cancel before reading the body. // Request.Body should still be readable after the context is canceled. cancel() b, err := ioutil.ReadAll(resp.Body) if err != nil || string(b) != requestBody { t.Fatalf("could not read body: %q %v", b, err) } } func TestCancelAfterHangingRequest(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.(http.Flusher).Flush() <-w.(http.CloseNotifier).CloseNotify() }) serv := httptest.NewServer(handler) defer serv.Close() ctx, cancel := context.WithCancel(context.Background()) resp, err := Get(ctx, nil, serv.URL) if err != nil { t.Fatalf("unexpected error in Get: %v", err) } // Cancel befer reading the body. // Reading Request.Body should fail, since the request was // canceled before anything was written. cancel() done := make(chan struct{}) go func() { b, err := ioutil.ReadAll(resp.Body) if len(b) != 0 || err == nil { t.Errorf(`Read got (%q, %v); want ("", error)`, b, err) } close(done) }() select { case <-time.After(1 * time.Second): t.Errorf("Test timed out") case <-done: } } func doRequest(ctx context.Context) (*http.Response, error) { var okHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { time.Sleep(requestDuration) w.Write([]byte(requestBody)) }) serv := httptest.NewServer(okHandler) defer serv.Close() return Get(ctx, nil, serv.URL) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/context/withtimeout_test.go000066400000000000000000000012451264464372400260760ustar00rootroot00000000000000// Copyright 2014 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 context_test import ( "fmt" "time" "golang.org/x/net/context" ) func ExampleWithTimeout() { // Pass a context with a timeout to tell a blocking function that it // should abandon its work after the timeout elapses. ctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond) select { case <-time.After(200 * time.Millisecond): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) // prints "context deadline exceeded" } // Output: // context deadline exceeded } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/dict/000077500000000000000000000000001264464372400213635ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/dict/dict.go000066400000000000000000000107541264464372400226440ustar00rootroot00000000000000// 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 "golang.org/x/net/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]) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/000077500000000000000000000000001264464372400214045ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/atom/000077500000000000000000000000001264464372400223445ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/atom/atom.go000066400000000000000000000044211264464372400236340ustar00rootroot00000000000000// Copyright 2012 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 atom provides integer codes (also known as atoms) for a fixed set of // frequently occurring HTML strings: tag names and attribute keys such as "p" // and "id". // // Sharing an atom's name between all elements with the same tag can result in // fewer string allocations when tokenizing and parsing HTML. Integer // comparisons are also generally faster than string comparisons. // // The value of an atom's particular code is not guaranteed to stay the same // between versions of this package. Neither is any ordering guaranteed: // whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to // be dense. The only guarantees are that e.g. looking up "div" will yield // atom.Div, calling atom.Div.String will return "div", and atom.Div != 0. package atom // import "golang.org/x/net/html/atom" // Atom is an integer code for a string. The zero value maps to "". type Atom uint32 // String returns the atom's name. func (a Atom) String() string { start := uint32(a >> 8) n := uint32(a & 0xff) if start+n > uint32(len(atomText)) { return "" } return atomText[start : start+n] } func (a Atom) string() string { return atomText[a>>8 : a>>8+a&0xff] } // fnv computes the FNV hash with an arbitrary starting value h. func fnv(h uint32, s []byte) uint32 { for i := range s { h ^= uint32(s[i]) h *= 16777619 } return h } func match(s string, t []byte) bool { for i, c := range t { if s[i] != c { return false } } return true } // Lookup returns the atom whose name is s. It returns zero if there is no // such atom. The lookup is case sensitive. func Lookup(s []byte) Atom { if len(s) == 0 || len(s) > maxAtomLen { return 0 } h := fnv(hash0, s) if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { return a } if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { return a } return 0 } // String returns a string whose contents are equal to s. In that sense, it is // equivalent to string(s) but may be more efficient. func String(s []byte) string { if a := Lookup(s); a != 0 { return a.String() } return string(s) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/atom/atom_test.go000066400000000000000000000041621264464372400246750ustar00rootroot00000000000000// Copyright 2012 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 atom import ( "sort" "testing" ) func TestKnown(t *testing.T) { for _, s := range testAtomList { if atom := Lookup([]byte(s)); atom.String() != s { t.Errorf("Lookup(%q) = %#x (%q)", s, uint32(atom), atom.String()) } } } func TestHits(t *testing.T) { for _, a := range table { if a == 0 { continue } got := Lookup([]byte(a.String())) if got != a { t.Errorf("Lookup(%q) = %#x, want %#x", a.String(), uint32(got), uint32(a)) } } } func TestMisses(t *testing.T) { testCases := []string{ "", "\x00", "\xff", "A", "DIV", "Div", "dIV", "aa", "a\x00", "ab", "abb", "abbr0", "abbr ", " abbr", " a", "acceptcharset", "acceptCharset", "accept_charset", "h0", "h1h2", "h7", "onClick", "λ", // The following string has the same hash (0xa1d7fab7) as "onmouseover". "\x00\x00\x00\x00\x00\x50\x18\xae\x38\xd0\xb7", } for _, tc := range testCases { got := Lookup([]byte(tc)) if got != 0 { t.Errorf("Lookup(%q): got %d, want 0", tc, got) } } } func TestForeignObject(t *testing.T) { const ( afo = Foreignobject afO = ForeignObject sfo = "foreignobject" sfO = "foreignObject" ) if got := Lookup([]byte(sfo)); got != afo { t.Errorf("Lookup(%q): got %#v, want %#v", sfo, got, afo) } if got := Lookup([]byte(sfO)); got != afO { t.Errorf("Lookup(%q): got %#v, want %#v", sfO, got, afO) } if got := afo.String(); got != sfo { t.Errorf("Atom(%#v).String(): got %q, want %q", afo, got, sfo) } if got := afO.String(); got != sfO { t.Errorf("Atom(%#v).String(): got %q, want %q", afO, got, sfO) } } func BenchmarkLookup(b *testing.B) { sortedTable := make([]string, 0, len(table)) for _, a := range table { if a != 0 { sortedTable = append(sortedTable, a.String()) } } sort.Strings(sortedTable) x := make([][]byte, 1000) for i := range x { x[i] = []byte(sortedTable[i%len(sortedTable)]) } b.ResetTimer() for i := 0; i < b.N; i++ { for _, s := range x { Lookup(s) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/atom/gen.go000066400000000000000000000242521264464372400234510ustar00rootroot00000000000000// Copyright 2012 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. // +build ignore package main // This program generates table.go and table_test.go. // Invoke as // // go run gen.go |gofmt >table.go // go run gen.go -test |gofmt >table_test.go import ( "flag" "fmt" "math/rand" "os" "sort" "strings" ) // identifier converts s to a Go exported identifier. // It converts "div" to "Div" and "accept-charset" to "AcceptCharset". func identifier(s string) string { b := make([]byte, 0, len(s)) cap := true for _, c := range s { if c == '-' { cap = true continue } if cap && 'a' <= c && c <= 'z' { c -= 'a' - 'A' } cap = false b = append(b, byte(c)) } return string(b) } var test = flag.Bool("test", false, "generate table_test.go") func main() { flag.Parse() var all []string all = append(all, elements...) all = append(all, attributes...) all = append(all, eventHandlers...) all = append(all, extra...) sort.Strings(all) if *test { fmt.Printf("// generated by go run gen.go -test; DO NOT EDIT\n\n") fmt.Printf("package atom\n\n") fmt.Printf("var testAtomList = []string{\n") for _, s := range all { fmt.Printf("\t%q,\n", s) } fmt.Printf("}\n") return } // uniq - lists have dups // compute max len too maxLen := 0 w := 0 for _, s := range all { if w == 0 || all[w-1] != s { if maxLen < len(s) { maxLen = len(s) } all[w] = s w++ } } all = all[:w] // Find hash that minimizes table size. var best *table for i := 0; i < 1000000; i++ { if best != nil && 1<<(best.k-1) < len(all) { break } h := rand.Uint32() for k := uint(0); k <= 16; k++ { if best != nil && k >= best.k { break } var t table if t.init(h, k, all) { best = &t break } } } if best == nil { fmt.Fprintf(os.Stderr, "failed to construct string table\n") os.Exit(1) } // Lay out strings, using overlaps when possible. layout := append([]string{}, all...) // Remove strings that are substrings of other strings for changed := true; changed; { changed = false for i, s := range layout { if s == "" { continue } for j, t := range layout { if i != j && t != "" && strings.Contains(s, t) { changed = true layout[j] = "" } } } } // Join strings where one suffix matches another prefix. for { // Find best i, j, k such that layout[i][len-k:] == layout[j][:k], // maximizing overlap length k. besti := -1 bestj := -1 bestk := 0 for i, s := range layout { if s == "" { continue } for j, t := range layout { if i == j { continue } for k := bestk + 1; k <= len(s) && k <= len(t); k++ { if s[len(s)-k:] == t[:k] { besti = i bestj = j bestk = k } } } } if bestk > 0 { layout[besti] += layout[bestj][bestk:] layout[bestj] = "" continue } break } text := strings.Join(layout, "") atom := map[string]uint32{} for _, s := range all { off := strings.Index(text, s) if off < 0 { panic("lost string " + s) } atom[s] = uint32(off<<8 | len(s)) } // Generate the Go code. fmt.Printf("// generated by go run gen.go; DO NOT EDIT\n\n") fmt.Printf("package atom\n\nconst (\n") for _, s := range all { fmt.Printf("\t%s Atom = %#x\n", identifier(s), atom[s]) } fmt.Printf(")\n\n") fmt.Printf("const hash0 = %#x\n\n", best.h0) fmt.Printf("const maxAtomLen = %d\n\n", maxLen) fmt.Printf("var table = [1<<%d]Atom{\n", best.k) for i, s := range best.tab { if s == "" { continue } fmt.Printf("\t%#x: %#x, // %s\n", i, atom[s], s) } fmt.Printf("}\n") datasize := (1 << best.k) * 4 fmt.Printf("const atomText =\n") textsize := len(text) for len(text) > 60 { fmt.Printf("\t%q +\n", text[:60]) text = text[60:] } fmt.Printf("\t%q\n\n", text) fmt.Fprintf(os.Stderr, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize) } type byLen []string func (x byLen) Less(i, j int) bool { return len(x[i]) > len(x[j]) } func (x byLen) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x byLen) Len() int { return len(x) } // fnv computes the FNV hash with an arbitrary starting value h. func fnv(h uint32, s string) uint32 { for i := 0; i < len(s); i++ { h ^= uint32(s[i]) h *= 16777619 } return h } // A table represents an attempt at constructing the lookup table. // The lookup table uses cuckoo hashing, meaning that each string // can be found in one of two positions. type table struct { h0 uint32 k uint mask uint32 tab []string } // hash returns the two hashes for s. func (t *table) hash(s string) (h1, h2 uint32) { h := fnv(t.h0, s) h1 = h & t.mask h2 = (h >> 16) & t.mask return } // init initializes the table with the given parameters. // h0 is the initial hash value, // k is the number of bits of hash value to use, and // x is the list of strings to store in the table. // init returns false if the table cannot be constructed. func (t *table) init(h0 uint32, k uint, x []string) bool { t.h0 = h0 t.k = k t.tab = make([]string, 1< len(t.tab) { return false } s := t.tab[i] h1, h2 := t.hash(s) j := h1 + h2 - i if t.tab[j] != "" && !t.push(j, depth+1) { return false } t.tab[j] = s return true } // The lists of element names and attribute keys were taken from // https://html.spec.whatwg.org/multipage/indices.html#index // as of the "HTML Living Standard - Last Updated 21 February 2015" version. var elements = []string{ "a", "abbr", "address", "area", "article", "aside", "audio", "b", "base", "bdi", "bdo", "blockquote", "body", "br", "button", "canvas", "caption", "cite", "code", "col", "colgroup", "command", "data", "datalist", "dd", "del", "details", "dfn", "dialog", "div", "dl", "dt", "em", "embed", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", "i", "iframe", "img", "input", "ins", "kbd", "keygen", "label", "legend", "li", "link", "map", "mark", "menu", "menuitem", "meta", "meter", "nav", "noscript", "object", "ol", "optgroup", "option", "output", "p", "param", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "script", "section", "select", "small", "source", "span", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "u", "ul", "var", "video", "wbr", } // https://html.spec.whatwg.org/multipage/indices.html#attributes-3 var attributes = []string{ "abbr", "accept", "accept-charset", "accesskey", "action", "alt", "async", "autocomplete", "autofocus", "autoplay", "challenge", "charset", "checked", "cite", "class", "cols", "colspan", "command", "content", "contenteditable", "contextmenu", "controls", "coords", "crossorigin", "data", "datetime", "default", "defer", "dir", "dirname", "disabled", "download", "draggable", "dropzone", "enctype", "for", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "headers", "height", "hidden", "high", "href", "hreflang", "http-equiv", "icon", "id", "inputmode", "ismap", "itemid", "itemprop", "itemref", "itemscope", "itemtype", "keytype", "kind", "label", "lang", "list", "loop", "low", "manifest", "max", "maxlength", "media", "mediagroup", "method", "min", "minlength", "multiple", "muted", "name", "novalidate", "open", "optimum", "pattern", "ping", "placeholder", "poster", "preload", "radiogroup", "readonly", "rel", "required", "reversed", "rows", "rowspan", "sandbox", "spellcheck", "scope", "scoped", "seamless", "selected", "shape", "size", "sizes", "sortable", "sorted", "span", "src", "srcdoc", "srclang", "start", "step", "style", "tabindex", "target", "title", "translate", "type", "typemustmatch", "usemap", "value", "width", "wrap", } var eventHandlers = []string{ "onabort", "onautocomplete", "onautocompleteerror", "onafterprint", "onbeforeprint", "onbeforeunload", "onblur", "oncancel", "oncanplay", "oncanplaythrough", "onchange", "onclick", "onclose", "oncontextmenu", "oncuechange", "ondblclick", "ondrag", "ondragend", "ondragenter", "ondragleave", "ondragover", "ondragstart", "ondrop", "ondurationchange", "onemptied", "onended", "onerror", "onfocus", "onhashchange", "oninput", "oninvalid", "onkeydown", "onkeypress", "onkeyup", "onlanguagechange", "onload", "onloadeddata", "onloadedmetadata", "onloadstart", "onmessage", "onmousedown", "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onmousewheel", "onoffline", "ononline", "onpagehide", "onpageshow", "onpause", "onplay", "onplaying", "onpopstate", "onprogress", "onratechange", "onreset", "onresize", "onscroll", "onseeked", "onseeking", "onselect", "onshow", "onsort", "onstalled", "onstorage", "onsubmit", "onsuspend", "ontimeupdate", "ontoggle", "onunload", "onvolumechange", "onwaiting", } // extra are ad-hoc values not covered by any of the lists above. var extra = []string{ "align", "annotation", "annotation-xml", "applet", "basefont", "bgsound", "big", "blink", "center", "color", "desc", "face", "font", "foreignObject", // HTML is case-insensitive, but SVG-embedded-in-HTML is case-sensitive. "foreignobject", "frame", "frameset", "image", "isindex", "listing", "malignmark", "marquee", "math", "mglyph", "mi", "mn", "mo", "ms", "mtext", "nobr", "noembed", "noframes", "plaintext", "prompt", "public", "spacer", "strike", "svg", "system", "tt", "xmp", } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/atom/table.go000066400000000000000000000551761264464372400240000ustar00rootroot00000000000000// generated by go run gen.go; DO NOT EDIT package atom const ( A Atom = 0x1 Abbr Atom = 0x4 Accept Atom = 0x2106 AcceptCharset Atom = 0x210e Accesskey Atom = 0x3309 Action Atom = 0x1f606 Address Atom = 0x4f307 Align Atom = 0x1105 Alt Atom = 0x4503 Annotation Atom = 0x1670a AnnotationXml Atom = 0x1670e Applet Atom = 0x2b306 Area Atom = 0x2fa04 Article Atom = 0x38807 Aside Atom = 0x8305 Async Atom = 0x7b05 Audio Atom = 0xa605 Autocomplete Atom = 0x1fc0c Autofocus Atom = 0xb309 Autoplay Atom = 0xce08 B Atom = 0x101 Base Atom = 0xd604 Basefont Atom = 0xd608 Bdi Atom = 0x1a03 Bdo Atom = 0xe703 Bgsound Atom = 0x11807 Big Atom = 0x12403 Blink Atom = 0x12705 Blockquote Atom = 0x12c0a Body Atom = 0x2f04 Br Atom = 0x202 Button Atom = 0x13606 Canvas Atom = 0x7f06 Caption Atom = 0x1bb07 Center Atom = 0x5b506 Challenge Atom = 0x21f09 Charset Atom = 0x2807 Checked Atom = 0x32807 Cite Atom = 0x3c804 Class Atom = 0x4de05 Code Atom = 0x14904 Col Atom = 0x15003 Colgroup Atom = 0x15008 Color Atom = 0x15d05 Cols Atom = 0x16204 Colspan Atom = 0x16207 Command Atom = 0x17507 Content Atom = 0x42307 Contenteditable Atom = 0x4230f Contextmenu Atom = 0x3310b Controls Atom = 0x18808 Coords Atom = 0x19406 Crossorigin Atom = 0x19f0b Data Atom = 0x44a04 Datalist Atom = 0x44a08 Datetime Atom = 0x23c08 Dd Atom = 0x26702 Default Atom = 0x8607 Defer Atom = 0x14b05 Del Atom = 0x3ef03 Desc Atom = 0x4db04 Details Atom = 0x4807 Dfn Atom = 0x6103 Dialog Atom = 0x1b06 Dir Atom = 0x6903 Dirname Atom = 0x6907 Disabled Atom = 0x10c08 Div Atom = 0x11303 Dl Atom = 0x11e02 Download Atom = 0x40008 Draggable Atom = 0x17b09 Dropzone Atom = 0x39108 Dt Atom = 0x50902 Em Atom = 0x6502 Embed Atom = 0x6505 Enctype Atom = 0x21107 Face Atom = 0x5b304 Fieldset Atom = 0x1b008 Figcaption Atom = 0x1b80a Figure Atom = 0x1cc06 Font Atom = 0xda04 Footer Atom = 0x8d06 For Atom = 0x1d803 ForeignObject Atom = 0x1d80d Foreignobject Atom = 0x1e50d Form Atom = 0x1f204 Formaction Atom = 0x1f20a Formenctype Atom = 0x20d0b Formmethod Atom = 0x2280a Formnovalidate Atom = 0x2320e Formtarget Atom = 0x2470a Frame Atom = 0x9a05 Frameset Atom = 0x9a08 H1 Atom = 0x26e02 H2 Atom = 0x29402 H3 Atom = 0x2a702 H4 Atom = 0x2e902 H5 Atom = 0x2f302 H6 Atom = 0x50b02 Head Atom = 0x2d504 Header Atom = 0x2d506 Headers Atom = 0x2d507 Height Atom = 0x25106 Hgroup Atom = 0x25906 Hidden Atom = 0x26506 High Atom = 0x26b04 Hr Atom = 0x27002 Href Atom = 0x27004 Hreflang Atom = 0x27008 Html Atom = 0x25504 HttpEquiv Atom = 0x2780a I Atom = 0x601 Icon Atom = 0x42204 Id Atom = 0x8502 Iframe Atom = 0x29606 Image Atom = 0x29c05 Img Atom = 0x2a103 Input Atom = 0x3e805 Inputmode Atom = 0x3e809 Ins Atom = 0x1a803 Isindex Atom = 0x2a907 Ismap Atom = 0x2b005 Itemid Atom = 0x33c06 Itemprop Atom = 0x3c908 Itemref Atom = 0x5ad07 Itemscope Atom = 0x2b909 Itemtype Atom = 0x2c308 Kbd Atom = 0x1903 Keygen Atom = 0x3906 Keytype Atom = 0x53707 Kind Atom = 0x10904 Label Atom = 0xf005 Lang Atom = 0x27404 Legend Atom = 0x18206 Li Atom = 0x1202 Link Atom = 0x12804 List Atom = 0x44e04 Listing Atom = 0x44e07 Loop Atom = 0xf404 Low Atom = 0x11f03 Malignmark Atom = 0x100a Manifest Atom = 0x5f108 Map Atom = 0x2b203 Mark Atom = 0x1604 Marquee Atom = 0x2cb07 Math Atom = 0x2d204 Max Atom = 0x2e103 Maxlength Atom = 0x2e109 Media Atom = 0x6e05 Mediagroup Atom = 0x6e0a Menu Atom = 0x33804 Menuitem Atom = 0x33808 Meta Atom = 0x45d04 Meter Atom = 0x24205 Method Atom = 0x22c06 Mglyph Atom = 0x2a206 Mi Atom = 0x2eb02 Min Atom = 0x2eb03 Minlength Atom = 0x2eb09 Mn Atom = 0x23502 Mo Atom = 0x3ed02 Ms Atom = 0x2bc02 Mtext Atom = 0x2f505 Multiple Atom = 0x30308 Muted Atom = 0x30b05 Name Atom = 0x6c04 Nav Atom = 0x3e03 Nobr Atom = 0x5704 Noembed Atom = 0x6307 Noframes Atom = 0x9808 Noscript Atom = 0x3d208 Novalidate Atom = 0x2360a Object Atom = 0x1ec06 Ol Atom = 0xc902 Onabort Atom = 0x13a07 Onafterprint Atom = 0x1c00c Onautocomplete Atom = 0x1fa0e Onautocompleteerror Atom = 0x1fa13 Onbeforeprint Atom = 0x6040d Onbeforeunload Atom = 0x4e70e Onblur Atom = 0xaa06 Oncancel Atom = 0xe908 Oncanplay Atom = 0x28509 Oncanplaythrough Atom = 0x28510 Onchange Atom = 0x3a708 Onclick Atom = 0x31007 Onclose Atom = 0x31707 Oncontextmenu Atom = 0x32f0d Oncuechange Atom = 0x3420b Ondblclick Atom = 0x34d0a Ondrag Atom = 0x35706 Ondragend Atom = 0x35709 Ondragenter Atom = 0x3600b Ondragleave Atom = 0x36b0b Ondragover Atom = 0x3760a Ondragstart Atom = 0x3800b Ondrop Atom = 0x38f06 Ondurationchange Atom = 0x39f10 Onemptied Atom = 0x39609 Onended Atom = 0x3af07 Onerror Atom = 0x3b607 Onfocus Atom = 0x3bd07 Onhashchange Atom = 0x3da0c Oninput Atom = 0x3e607 Oninvalid Atom = 0x3f209 Onkeydown Atom = 0x3fb09 Onkeypress Atom = 0x4080a Onkeyup Atom = 0x41807 Onlanguagechange Atom = 0x43210 Onload Atom = 0x44206 Onloadeddata Atom = 0x4420c Onloadedmetadata Atom = 0x45510 Onloadstart Atom = 0x46b0b Onmessage Atom = 0x47609 Onmousedown Atom = 0x47f0b Onmousemove Atom = 0x48a0b Onmouseout Atom = 0x4950a Onmouseover Atom = 0x4a20b Onmouseup Atom = 0x4ad09 Onmousewheel Atom = 0x4b60c Onoffline Atom = 0x4c209 Ononline Atom = 0x4cb08 Onpagehide Atom = 0x4d30a Onpageshow Atom = 0x4fe0a Onpause Atom = 0x50d07 Onplay Atom = 0x51706 Onplaying Atom = 0x51709 Onpopstate Atom = 0x5200a Onprogress Atom = 0x52a0a Onratechange Atom = 0x53e0c Onreset Atom = 0x54a07 Onresize Atom = 0x55108 Onscroll Atom = 0x55f08 Onseeked Atom = 0x56708 Onseeking Atom = 0x56f09 Onselect Atom = 0x57808 Onshow Atom = 0x58206 Onsort Atom = 0x58b06 Onstalled Atom = 0x59509 Onstorage Atom = 0x59e09 Onsubmit Atom = 0x5a708 Onsuspend Atom = 0x5bb09 Ontimeupdate Atom = 0xdb0c Ontoggle Atom = 0x5c408 Onunload Atom = 0x5cc08 Onvolumechange Atom = 0x5d40e Onwaiting Atom = 0x5e209 Open Atom = 0x3cf04 Optgroup Atom = 0xf608 Optimum Atom = 0x5eb07 Option Atom = 0x60006 Output Atom = 0x49c06 P Atom = 0xc01 Param Atom = 0xc05 Pattern Atom = 0x5107 Ping Atom = 0x7704 Placeholder Atom = 0xc30b Plaintext Atom = 0xfd09 Poster Atom = 0x15706 Pre Atom = 0x25e03 Preload Atom = 0x25e07 Progress Atom = 0x52c08 Prompt Atom = 0x5fa06 Public Atom = 0x41e06 Q Atom = 0x13101 Radiogroup Atom = 0x30a Readonly Atom = 0x2fb08 Rel Atom = 0x25f03 Required Atom = 0x1d008 Reversed Atom = 0x5a08 Rows Atom = 0x9204 Rowspan Atom = 0x9207 Rp Atom = 0x1c602 Rt Atom = 0x13f02 Ruby Atom = 0xaf04 S Atom = 0x2c01 Samp Atom = 0x4e04 Sandbox Atom = 0xbb07 Scope Atom = 0x2bd05 Scoped Atom = 0x2bd06 Script Atom = 0x3d406 Seamless Atom = 0x31c08 Section Atom = 0x4e207 Select Atom = 0x57a06 Selected Atom = 0x57a08 Shape Atom = 0x4f905 Size Atom = 0x55504 Sizes Atom = 0x55505 Small Atom = 0x18f05 Sortable Atom = 0x58d08 Sorted Atom = 0x19906 Source Atom = 0x1aa06 Spacer Atom = 0x2db06 Span Atom = 0x9504 Spellcheck Atom = 0x3230a Src Atom = 0x3c303 Srcdoc Atom = 0x3c306 Srclang Atom = 0x41107 Start Atom = 0x38605 Step Atom = 0x5f704 Strike Atom = 0x53306 Strong Atom = 0x55906 Style Atom = 0x61105 Sub Atom = 0x5a903 Summary Atom = 0x61607 Sup Atom = 0x61d03 Svg Atom = 0x62003 System Atom = 0x62306 Tabindex Atom = 0x46308 Table Atom = 0x42d05 Target Atom = 0x24b06 Tbody Atom = 0x2e05 Td Atom = 0x4702 Template Atom = 0x62608 Textarea Atom = 0x2f608 Tfoot Atom = 0x8c05 Th Atom = 0x22e02 Thead Atom = 0x2d405 Time Atom = 0xdd04 Title Atom = 0xa105 Tr Atom = 0x10502 Track Atom = 0x10505 Translate Atom = 0x14009 Tt Atom = 0x5302 Type Atom = 0x21404 Typemustmatch Atom = 0x2140d U Atom = 0xb01 Ul Atom = 0x8a02 Usemap Atom = 0x51106 Value Atom = 0x4005 Var Atom = 0x11503 Video Atom = 0x28105 Wbr Atom = 0x12103 Width Atom = 0x50705 Wrap Atom = 0x58704 Xmp Atom = 0xc103 ) const hash0 = 0xc17da63e const maxAtomLen = 19 var table = [1 << 9]Atom{ 0x1: 0x48a0b, // onmousemove 0x2: 0x5e209, // onwaiting 0x3: 0x1fa13, // onautocompleteerror 0x4: 0x5fa06, // prompt 0x7: 0x5eb07, // optimum 0x8: 0x1604, // mark 0xa: 0x5ad07, // itemref 0xb: 0x4fe0a, // onpageshow 0xc: 0x57a06, // select 0xd: 0x17b09, // draggable 0xe: 0x3e03, // nav 0xf: 0x17507, // command 0x11: 0xb01, // u 0x14: 0x2d507, // headers 0x15: 0x44a08, // datalist 0x17: 0x4e04, // samp 0x1a: 0x3fb09, // onkeydown 0x1b: 0x55f08, // onscroll 0x1c: 0x15003, // col 0x20: 0x3c908, // itemprop 0x21: 0x2780a, // http-equiv 0x22: 0x61d03, // sup 0x24: 0x1d008, // required 0x2b: 0x25e07, // preload 0x2c: 0x6040d, // onbeforeprint 0x2d: 0x3600b, // ondragenter 0x2e: 0x50902, // dt 0x2f: 0x5a708, // onsubmit 0x30: 0x27002, // hr 0x31: 0x32f0d, // oncontextmenu 0x33: 0x29c05, // image 0x34: 0x50d07, // onpause 0x35: 0x25906, // hgroup 0x36: 0x7704, // ping 0x37: 0x57808, // onselect 0x3a: 0x11303, // div 0x3b: 0x1fa0e, // onautocomplete 0x40: 0x2eb02, // mi 0x41: 0x31c08, // seamless 0x42: 0x2807, // charset 0x43: 0x8502, // id 0x44: 0x5200a, // onpopstate 0x45: 0x3ef03, // del 0x46: 0x2cb07, // marquee 0x47: 0x3309, // accesskey 0x49: 0x8d06, // footer 0x4a: 0x44e04, // list 0x4b: 0x2b005, // ismap 0x51: 0x33804, // menu 0x52: 0x2f04, // body 0x55: 0x9a08, // frameset 0x56: 0x54a07, // onreset 0x57: 0x12705, // blink 0x58: 0xa105, // title 0x59: 0x38807, // article 0x5b: 0x22e02, // th 0x5d: 0x13101, // q 0x5e: 0x3cf04, // open 0x5f: 0x2fa04, // area 0x61: 0x44206, // onload 0x62: 0xda04, // font 0x63: 0xd604, // base 0x64: 0x16207, // colspan 0x65: 0x53707, // keytype 0x66: 0x11e02, // dl 0x68: 0x1b008, // fieldset 0x6a: 0x2eb03, // min 0x6b: 0x11503, // var 0x6f: 0x2d506, // header 0x70: 0x13f02, // rt 0x71: 0x15008, // colgroup 0x72: 0x23502, // mn 0x74: 0x13a07, // onabort 0x75: 0x3906, // keygen 0x76: 0x4c209, // onoffline 0x77: 0x21f09, // challenge 0x78: 0x2b203, // map 0x7a: 0x2e902, // h4 0x7b: 0x3b607, // onerror 0x7c: 0x2e109, // maxlength 0x7d: 0x2f505, // mtext 0x7e: 0xbb07, // sandbox 0x7f: 0x58b06, // onsort 0x80: 0x100a, // malignmark 0x81: 0x45d04, // meta 0x82: 0x7b05, // async 0x83: 0x2a702, // h3 0x84: 0x26702, // dd 0x85: 0x27004, // href 0x86: 0x6e0a, // mediagroup 0x87: 0x19406, // coords 0x88: 0x41107, // srclang 0x89: 0x34d0a, // ondblclick 0x8a: 0x4005, // value 0x8c: 0xe908, // oncancel 0x8e: 0x3230a, // spellcheck 0x8f: 0x9a05, // frame 0x91: 0x12403, // big 0x94: 0x1f606, // action 0x95: 0x6903, // dir 0x97: 0x2fb08, // readonly 0x99: 0x42d05, // table 0x9a: 0x61607, // summary 0x9b: 0x12103, // wbr 0x9c: 0x30a, // radiogroup 0x9d: 0x6c04, // name 0x9f: 0x62306, // system 0xa1: 0x15d05, // color 0xa2: 0x7f06, // canvas 0xa3: 0x25504, // html 0xa5: 0x56f09, // onseeking 0xac: 0x4f905, // shape 0xad: 0x25f03, // rel 0xae: 0x28510, // oncanplaythrough 0xaf: 0x3760a, // ondragover 0xb0: 0x62608, // template 0xb1: 0x1d80d, // foreignObject 0xb3: 0x9204, // rows 0xb6: 0x44e07, // listing 0xb7: 0x49c06, // output 0xb9: 0x3310b, // contextmenu 0xbb: 0x11f03, // low 0xbc: 0x1c602, // rp 0xbd: 0x5bb09, // onsuspend 0xbe: 0x13606, // button 0xbf: 0x4db04, // desc 0xc1: 0x4e207, // section 0xc2: 0x52a0a, // onprogress 0xc3: 0x59e09, // onstorage 0xc4: 0x2d204, // math 0xc5: 0x4503, // alt 0xc7: 0x8a02, // ul 0xc8: 0x5107, // pattern 0xc9: 0x4b60c, // onmousewheel 0xca: 0x35709, // ondragend 0xcb: 0xaf04, // ruby 0xcc: 0xc01, // p 0xcd: 0x31707, // onclose 0xce: 0x24205, // meter 0xcf: 0x11807, // bgsound 0xd2: 0x25106, // height 0xd4: 0x101, // b 0xd5: 0x2c308, // itemtype 0xd8: 0x1bb07, // caption 0xd9: 0x10c08, // disabled 0xdb: 0x33808, // menuitem 0xdc: 0x62003, // svg 0xdd: 0x18f05, // small 0xde: 0x44a04, // data 0xe0: 0x4cb08, // ononline 0xe1: 0x2a206, // mglyph 0xe3: 0x6505, // embed 0xe4: 0x10502, // tr 0xe5: 0x46b0b, // onloadstart 0xe7: 0x3c306, // srcdoc 0xeb: 0x5c408, // ontoggle 0xed: 0xe703, // bdo 0xee: 0x4702, // td 0xef: 0x8305, // aside 0xf0: 0x29402, // h2 0xf1: 0x52c08, // progress 0xf2: 0x12c0a, // blockquote 0xf4: 0xf005, // label 0xf5: 0x601, // i 0xf7: 0x9207, // rowspan 0xfb: 0x51709, // onplaying 0xfd: 0x2a103, // img 0xfe: 0xf608, // optgroup 0xff: 0x42307, // content 0x101: 0x53e0c, // onratechange 0x103: 0x3da0c, // onhashchange 0x104: 0x4807, // details 0x106: 0x40008, // download 0x109: 0x14009, // translate 0x10b: 0x4230f, // contenteditable 0x10d: 0x36b0b, // ondragleave 0x10e: 0x2106, // accept 0x10f: 0x57a08, // selected 0x112: 0x1f20a, // formaction 0x113: 0x5b506, // center 0x115: 0x45510, // onloadedmetadata 0x116: 0x12804, // link 0x117: 0xdd04, // time 0x118: 0x19f0b, // crossorigin 0x119: 0x3bd07, // onfocus 0x11a: 0x58704, // wrap 0x11b: 0x42204, // icon 0x11d: 0x28105, // video 0x11e: 0x4de05, // class 0x121: 0x5d40e, // onvolumechange 0x122: 0xaa06, // onblur 0x123: 0x2b909, // itemscope 0x124: 0x61105, // style 0x127: 0x41e06, // public 0x129: 0x2320e, // formnovalidate 0x12a: 0x58206, // onshow 0x12c: 0x51706, // onplay 0x12d: 0x3c804, // cite 0x12e: 0x2bc02, // ms 0x12f: 0xdb0c, // ontimeupdate 0x130: 0x10904, // kind 0x131: 0x2470a, // formtarget 0x135: 0x3af07, // onended 0x136: 0x26506, // hidden 0x137: 0x2c01, // s 0x139: 0x2280a, // formmethod 0x13a: 0x3e805, // input 0x13c: 0x50b02, // h6 0x13d: 0xc902, // ol 0x13e: 0x3420b, // oncuechange 0x13f: 0x1e50d, // foreignobject 0x143: 0x4e70e, // onbeforeunload 0x144: 0x2bd05, // scope 0x145: 0x39609, // onemptied 0x146: 0x14b05, // defer 0x147: 0xc103, // xmp 0x148: 0x39f10, // ondurationchange 0x149: 0x1903, // kbd 0x14c: 0x47609, // onmessage 0x14d: 0x60006, // option 0x14e: 0x2eb09, // minlength 0x14f: 0x32807, // checked 0x150: 0xce08, // autoplay 0x152: 0x202, // br 0x153: 0x2360a, // novalidate 0x156: 0x6307, // noembed 0x159: 0x31007, // onclick 0x15a: 0x47f0b, // onmousedown 0x15b: 0x3a708, // onchange 0x15e: 0x3f209, // oninvalid 0x15f: 0x2bd06, // scoped 0x160: 0x18808, // controls 0x161: 0x30b05, // muted 0x162: 0x58d08, // sortable 0x163: 0x51106, // usemap 0x164: 0x1b80a, // figcaption 0x165: 0x35706, // ondrag 0x166: 0x26b04, // high 0x168: 0x3c303, // src 0x169: 0x15706, // poster 0x16b: 0x1670e, // annotation-xml 0x16c: 0x5f704, // step 0x16d: 0x4, // abbr 0x16e: 0x1b06, // dialog 0x170: 0x1202, // li 0x172: 0x3ed02, // mo 0x175: 0x1d803, // for 0x176: 0x1a803, // ins 0x178: 0x55504, // size 0x179: 0x43210, // onlanguagechange 0x17a: 0x8607, // default 0x17b: 0x1a03, // bdi 0x17c: 0x4d30a, // onpagehide 0x17d: 0x6907, // dirname 0x17e: 0x21404, // type 0x17f: 0x1f204, // form 0x181: 0x28509, // oncanplay 0x182: 0x6103, // dfn 0x183: 0x46308, // tabindex 0x186: 0x6502, // em 0x187: 0x27404, // lang 0x189: 0x39108, // dropzone 0x18a: 0x4080a, // onkeypress 0x18b: 0x23c08, // datetime 0x18c: 0x16204, // cols 0x18d: 0x1, // a 0x18e: 0x4420c, // onloadeddata 0x190: 0xa605, // audio 0x192: 0x2e05, // tbody 0x193: 0x22c06, // method 0x195: 0xf404, // loop 0x196: 0x29606, // iframe 0x198: 0x2d504, // head 0x19e: 0x5f108, // manifest 0x19f: 0xb309, // autofocus 0x1a0: 0x14904, // code 0x1a1: 0x55906, // strong 0x1a2: 0x30308, // multiple 0x1a3: 0xc05, // param 0x1a6: 0x21107, // enctype 0x1a7: 0x5b304, // face 0x1a8: 0xfd09, // plaintext 0x1a9: 0x26e02, // h1 0x1aa: 0x59509, // onstalled 0x1ad: 0x3d406, // script 0x1ae: 0x2db06, // spacer 0x1af: 0x55108, // onresize 0x1b0: 0x4a20b, // onmouseover 0x1b1: 0x5cc08, // onunload 0x1b2: 0x56708, // onseeked 0x1b4: 0x2140d, // typemustmatch 0x1b5: 0x1cc06, // figure 0x1b6: 0x4950a, // onmouseout 0x1b7: 0x25e03, // pre 0x1b8: 0x50705, // width 0x1b9: 0x19906, // sorted 0x1bb: 0x5704, // nobr 0x1be: 0x5302, // tt 0x1bf: 0x1105, // align 0x1c0: 0x3e607, // oninput 0x1c3: 0x41807, // onkeyup 0x1c6: 0x1c00c, // onafterprint 0x1c7: 0x210e, // accept-charset 0x1c8: 0x33c06, // itemid 0x1c9: 0x3e809, // inputmode 0x1cb: 0x53306, // strike 0x1cc: 0x5a903, // sub 0x1cd: 0x10505, // track 0x1ce: 0x38605, // start 0x1d0: 0xd608, // basefont 0x1d6: 0x1aa06, // source 0x1d7: 0x18206, // legend 0x1d8: 0x2d405, // thead 0x1da: 0x8c05, // tfoot 0x1dd: 0x1ec06, // object 0x1de: 0x6e05, // media 0x1df: 0x1670a, // annotation 0x1e0: 0x20d0b, // formenctype 0x1e2: 0x3d208, // noscript 0x1e4: 0x55505, // sizes 0x1e5: 0x1fc0c, // autocomplete 0x1e6: 0x9504, // span 0x1e7: 0x9808, // noframes 0x1e8: 0x24b06, // target 0x1e9: 0x38f06, // ondrop 0x1ea: 0x2b306, // applet 0x1ec: 0x5a08, // reversed 0x1f0: 0x2a907, // isindex 0x1f3: 0x27008, // hreflang 0x1f5: 0x2f302, // h5 0x1f6: 0x4f307, // address 0x1fa: 0x2e103, // max 0x1fb: 0xc30b, // placeholder 0x1fc: 0x2f608, // textarea 0x1fe: 0x4ad09, // onmouseup 0x1ff: 0x3800b, // ondragstart } const atomText = "abbradiogrouparamalignmarkbdialogaccept-charsetbodyaccesskey" + "genavaluealtdetailsampatternobreversedfnoembedirnamediagroup" + "ingasyncanvasidefaultfooterowspanoframesetitleaudionblurubya" + "utofocusandboxmplaceholderautoplaybasefontimeupdatebdoncance" + "labelooptgrouplaintextrackindisabledivarbgsoundlowbrbigblink" + "blockquotebuttonabortranslatecodefercolgroupostercolorcolspa" + "nnotation-xmlcommandraggablegendcontrolsmallcoordsortedcross" + "originsourcefieldsetfigcaptionafterprintfigurequiredforeignO" + "bjectforeignobjectformactionautocompleteerrorformenctypemust" + "matchallengeformmethodformnovalidatetimeterformtargetheightm" + "lhgroupreloadhiddenhigh1hreflanghttp-equivideoncanplaythroug" + "h2iframeimageimglyph3isindexismappletitemscopeditemtypemarqu" + "eematheaderspacermaxlength4minlength5mtextareadonlymultiplem" + "utedonclickoncloseamlesspellcheckedoncontextmenuitemidoncuec" + "hangeondblclickondragendondragenterondragleaveondragoverondr" + "agstarticleondropzonemptiedondurationchangeonendedonerroronf" + "ocusrcdocitempropenoscriptonhashchangeoninputmodeloninvalido" + "nkeydownloadonkeypressrclangonkeyupublicontenteditableonlang" + "uagechangeonloadeddatalistingonloadedmetadatabindexonloadsta" + "rtonmessageonmousedownonmousemoveonmouseoutputonmouseoveronm" + "ouseuponmousewheelonofflineononlineonpagehidesclassectionbef" + "oreunloaddresshapeonpageshowidth6onpausemaponplayingonpopsta" + "teonprogresstrikeytypeonratechangeonresetonresizestrongonscr" + "ollonseekedonseekingonselectedonshowraponsortableonstalledon" + "storageonsubmitemrefacenteronsuspendontoggleonunloadonvolume" + "changeonwaitingoptimumanifestepromptoptionbeforeprintstylesu" + "mmarysupsvgsystemplate" golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/atom/table_test.go000066400000000000000000000077371264464372400250370ustar00rootroot00000000000000// generated by go run gen.go -test; DO NOT EDIT package atom var testAtomList = []string{ "a", "abbr", "abbr", "accept", "accept-charset", "accesskey", "action", "address", "align", "alt", "annotation", "annotation-xml", "applet", "area", "article", "aside", "async", "audio", "autocomplete", "autofocus", "autoplay", "b", "base", "basefont", "bdi", "bdo", "bgsound", "big", "blink", "blockquote", "body", "br", "button", "canvas", "caption", "center", "challenge", "charset", "checked", "cite", "cite", "class", "code", "col", "colgroup", "color", "cols", "colspan", "command", "command", "content", "contenteditable", "contextmenu", "controls", "coords", "crossorigin", "data", "data", "datalist", "datetime", "dd", "default", "defer", "del", "desc", "details", "dfn", "dialog", "dir", "dirname", "disabled", "div", "dl", "download", "draggable", "dropzone", "dt", "em", "embed", "enctype", "face", "fieldset", "figcaption", "figure", "font", "footer", "for", "foreignObject", "foreignobject", "form", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "frame", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "headers", "height", "hgroup", "hidden", "high", "hr", "href", "hreflang", "html", "http-equiv", "i", "icon", "id", "iframe", "image", "img", "input", "inputmode", "ins", "isindex", "ismap", "itemid", "itemprop", "itemref", "itemscope", "itemtype", "kbd", "keygen", "keytype", "kind", "label", "label", "lang", "legend", "li", "link", "list", "listing", "loop", "low", "malignmark", "manifest", "map", "mark", "marquee", "math", "max", "maxlength", "media", "mediagroup", "menu", "menuitem", "meta", "meter", "method", "mglyph", "mi", "min", "minlength", "mn", "mo", "ms", "mtext", "multiple", "muted", "name", "nav", "nobr", "noembed", "noframes", "noscript", "novalidate", "object", "ol", "onabort", "onafterprint", "onautocomplete", "onautocompleteerror", "onbeforeprint", "onbeforeunload", "onblur", "oncancel", "oncanplay", "oncanplaythrough", "onchange", "onclick", "onclose", "oncontextmenu", "oncuechange", "ondblclick", "ondrag", "ondragend", "ondragenter", "ondragleave", "ondragover", "ondragstart", "ondrop", "ondurationchange", "onemptied", "onended", "onerror", "onfocus", "onhashchange", "oninput", "oninvalid", "onkeydown", "onkeypress", "onkeyup", "onlanguagechange", "onload", "onloadeddata", "onloadedmetadata", "onloadstart", "onmessage", "onmousedown", "onmousemove", "onmouseout", "onmouseover", "onmouseup", "onmousewheel", "onoffline", "ononline", "onpagehide", "onpageshow", "onpause", "onplay", "onplaying", "onpopstate", "onprogress", "onratechange", "onreset", "onresize", "onscroll", "onseeked", "onseeking", "onselect", "onshow", "onsort", "onstalled", "onstorage", "onsubmit", "onsuspend", "ontimeupdate", "ontoggle", "onunload", "onvolumechange", "onwaiting", "open", "optgroup", "optimum", "option", "output", "p", "param", "pattern", "ping", "placeholder", "plaintext", "poster", "pre", "preload", "progress", "prompt", "public", "q", "radiogroup", "readonly", "rel", "required", "reversed", "rows", "rowspan", "rp", "rt", "ruby", "s", "samp", "sandbox", "scope", "scoped", "script", "seamless", "section", "select", "selected", "shape", "size", "sizes", "small", "sortable", "sorted", "source", "spacer", "span", "span", "spellcheck", "src", "srcdoc", "srclang", "start", "step", "strike", "strong", "style", "style", "sub", "summary", "sup", "svg", "system", "tabindex", "table", "target", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "title", "tr", "track", "translate", "tt", "type", "typemustmatch", "u", "ul", "usemap", "value", "var", "video", "wbr", "width", "wrap", "xmp", } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/000077500000000000000000000000001264464372400230355ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/charset.go000066400000000000000000000140731264464372400250220ustar00rootroot00000000000000// Copyright 2013 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 charset provides common text encodings for HTML documents. // // The mapping from encoding labels to encodings is defined at // https://encoding.spec.whatwg.org/. package charset // import "golang.org/x/net/html/charset" import ( "bytes" "fmt" "io" "mime" "strings" "unicode/utf8" "golang.org/x/net/html" "golang.org/x/text/encoding" "golang.org/x/text/encoding/charmap" "golang.org/x/text/encoding/htmlindex" "golang.org/x/text/transform" ) // Lookup returns the encoding with the specified label, and its canonical // name. It returns nil and the empty string if label is not one of the // standard encodings for HTML. Matching is case-insensitive and ignores // leading and trailing whitespace. Encoders will use HTML escape sequences for // runes that are not supported by the character set. func Lookup(label string) (e encoding.Encoding, name string) { e, err := htmlindex.Get(label) if err != nil { return nil, "" } name, _ = htmlindex.Name(e) return &htmlEncoding{e}, name } type htmlEncoding struct{ encoding.Encoding } func (h *htmlEncoding) NewEncoder() *encoding.Encoder { // HTML requires a non-terminating legacy encoder. We use HTML escapes to // substitute unsupported code points. return encoding.HTMLEscapeUnsupported(h.Encoding.NewEncoder()) } // DetermineEncoding determines the encoding of an HTML document by examining // up to the first 1024 bytes of content and the declared Content-Type. // // See http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#determining-the-character-encoding func DetermineEncoding(content []byte, contentType string) (e encoding.Encoding, name string, certain bool) { if len(content) > 1024 { content = content[:1024] } for _, b := range boms { if bytes.HasPrefix(content, b.bom) { e, name = Lookup(b.enc) return e, name, true } } if _, params, err := mime.ParseMediaType(contentType); err == nil { if cs, ok := params["charset"]; ok { if e, name = Lookup(cs); e != nil { return e, name, true } } } if len(content) > 0 { e, name = prescan(content) if e != nil { return e, name, false } } // Try to detect UTF-8. // First eliminate any partial rune at the end. for i := len(content) - 1; i >= 0 && i > len(content)-4; i-- { b := content[i] if b < 0x80 { break } if utf8.RuneStart(b) { content = content[:i] break } } hasHighBit := false for _, c := range content { if c >= 0x80 { hasHighBit = true break } } if hasHighBit && utf8.Valid(content) { return encoding.Nop, "utf-8", false } // TODO: change default depending on user's locale? return charmap.Windows1252, "windows-1252", false } // NewReader returns an io.Reader that converts the content of r to UTF-8. // It calls DetermineEncoding to find out what r's encoding is. func NewReader(r io.Reader, contentType string) (io.Reader, error) { preview := make([]byte, 1024) n, err := io.ReadFull(r, preview) switch { case err == io.ErrUnexpectedEOF: preview = preview[:n] r = bytes.NewReader(preview) case err != nil: return nil, err default: r = io.MultiReader(bytes.NewReader(preview), r) } if e, _, _ := DetermineEncoding(preview, contentType); e != encoding.Nop { r = transform.NewReader(r, e.NewDecoder()) } return r, nil } // NewReaderLabel returns a reader that converts from the specified charset to // UTF-8. It uses Lookup to find the encoding that corresponds to label, and // returns an error if Lookup returns nil. It is suitable for use as // encoding/xml.Decoder's CharsetReader function. func NewReaderLabel(label string, input io.Reader) (io.Reader, error) { e, _ := Lookup(label) if e == nil { return nil, fmt.Errorf("unsupported charset: %q", label) } return transform.NewReader(input, e.NewDecoder()), nil } func prescan(content []byte) (e encoding.Encoding, name string) { z := html.NewTokenizer(bytes.NewReader(content)) for { switch z.Next() { case html.ErrorToken: return nil, "" case html.StartTagToken, html.SelfClosingTagToken: tagName, hasAttr := z.TagName() if !bytes.Equal(tagName, []byte("meta")) { continue } attrList := make(map[string]bool) gotPragma := false const ( dontKnow = iota doNeedPragma doNotNeedPragma ) needPragma := dontKnow name = "" e = nil for hasAttr { var key, val []byte key, val, hasAttr = z.TagAttr() ks := string(key) if attrList[ks] { continue } attrList[ks] = true for i, c := range val { if 'A' <= c && c <= 'Z' { val[i] = c + 0x20 } } switch ks { case "http-equiv": if bytes.Equal(val, []byte("content-type")) { gotPragma = true } case "content": if e == nil { name = fromMetaElement(string(val)) if name != "" { e, name = Lookup(name) if e != nil { needPragma = doNeedPragma } } } case "charset": e, name = Lookup(string(val)) needPragma = doNotNeedPragma } } if needPragma == dontKnow || needPragma == doNeedPragma && !gotPragma { continue } if strings.HasPrefix(name, "utf-16") { name = "utf-8" e = encoding.Nop } if e != nil { return e, name } } } } func fromMetaElement(s string) string { for s != "" { csLoc := strings.Index(s, "charset") if csLoc == -1 { return "" } s = s[csLoc+len("charset"):] s = strings.TrimLeft(s, " \t\n\f\r") if !strings.HasPrefix(s, "=") { continue } s = s[1:] s = strings.TrimLeft(s, " \t\n\f\r") if s == "" { return "" } if q := s[0]; q == '"' || q == '\'' { s = s[1:] closeQuote := strings.IndexRune(s, rune(q)) if closeQuote == -1 { return "" } return s[:closeQuote] } end := strings.IndexAny(s, "; \t\n\f\r") if end == -1 { end = len(s) } return s[:end] } return "" } var boms = []struct { bom []byte enc string }{ {[]byte{0xfe, 0xff}, "utf-16be"}, {[]byte{0xff, 0xfe}, "utf-16le"}, {[]byte{0xef, 0xbb, 0xbf}, "utf-8"}, } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/charset_test.go000066400000000000000000000177411264464372400260660ustar00rootroot00000000000000// Copyright 2013 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 charset import ( "bytes" "encoding/xml" "io/ioutil" "runtime" "strings" "testing" "golang.org/x/text/transform" ) func transformString(t transform.Transformer, s string) (string, error) { r := transform.NewReader(strings.NewReader(s), t) b, err := ioutil.ReadAll(r) return string(b), err } type testCase struct { utf8, other, otherEncoding string } // testCases for encoding and decoding. var testCases = []testCase{ {"Résumé", "Résumé", "utf8"}, {"Résumé", "R\xe9sum\xe9", "latin1"}, {"ã“ã‚Œã¯æ¼¢å­—ã§ã™ã€‚", "S0\x8c0o0\"oW[g0Y0\x020", "UTF-16LE"}, {"ã“ã‚Œã¯æ¼¢å­—ã§ã™ã€‚", "0S0\x8c0oo\"[W0g0Y0\x02", "UTF-16BE"}, {"Hello, world", "Hello, world", "ASCII"}, {"GdaÅ„sk", "Gda\xf1sk", "ISO-8859-2"}, {"Ââ ÄŒÄ ÄÄ‘ ÅŠÅ‹ Õõ Å Å¡ Žž Ã…Ã¥ Ää", "\xc2\xe2 \xc8\xe8 \xa9\xb9 \xaf\xbf \xd5\xf5 \xaa\xba \xac\xbc \xc5\xe5 \xc4\xe4", "ISO-8859-10"}, {"สำหรับ", "\xca\xd3\xcb\xc3\u047a", "ISO-8859-11"}, {"latvieÅ¡u", "latvie\xf0u", "ISO-8859-13"}, {"Seònaid", "Se\xf2naid", "ISO-8859-14"}, {"€1 is cheap", "\xa41 is cheap", "ISO-8859-15"}, {"româneÈ™te", "rom\xe2ne\xbate", "ISO-8859-16"}, {"nutraĵo", "nutra\xbco", "ISO-8859-3"}, {"Kalâdlit", "Kal\xe2dlit", "ISO-8859-4"}, {"руÑÑкий", "\xe0\xe3\xe1\xe1\xda\xd8\xd9", "ISO-8859-5"}, {"ελληνικά", "\xe5\xeb\xeb\xe7\xed\xe9\xea\xdc", "ISO-8859-7"}, {"KaÄŸan", "Ka\xf0an", "ISO-8859-9"}, {"Résumé", "R\x8esum\x8e", "macintosh"}, {"GdaÅ„sk", "Gda\xf1sk", "windows-1250"}, {"руÑÑкий", "\xf0\xf3\xf1\xf1\xea\xe8\xe9", "windows-1251"}, {"Résumé", "R\xe9sum\xe9", "windows-1252"}, {"ελληνικά", "\xe5\xeb\xeb\xe7\xed\xe9\xea\xdc", "windows-1253"}, {"KaÄŸan", "Ka\xf0an", "windows-1254"}, {"עִבְרִית", "\xf2\xc4\xe1\xc0\xf8\xc4\xe9\xfa", "windows-1255"}, {"العربية", "\xc7\xe1\xda\xd1\xc8\xed\xc9", "windows-1256"}, {"latvieÅ¡u", "latvie\xf0u", "windows-1257"}, {"Việt", "Vi\xea\xf2t", "windows-1258"}, {"สำหรับ", "\xca\xd3\xcb\xc3\u047a", "windows-874"}, {"руÑÑкий", "\xd2\xd5\xd3\xd3\xcb\xc9\xca", "KOI8-R"}, {"українÑька", "\xd5\xcb\xd2\xc1\xa7\xce\xd3\xd8\xcb\xc1", "KOI8-U"}, {"Hello 常用國字標準字體表", "Hello \xb1`\xa5\u03b0\xea\xa6r\xbc\u0437\u01e6r\xc5\xe9\xaa\xed", "big5"}, {"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gbk"}, {"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gb18030"}, {"עִבְרִית", "\x81\x30\xfb\x30\x81\x30\xf6\x34\x81\x30\xf9\x33\x81\x30\xf6\x30\x81\x30\xfb\x36\x81\x30\xf6\x34\x81\x30\xfa\x31\x81\x30\xfb\x38", "gb18030"}, {"㧯", "\x82\x31\x89\x38", "gb18030"}, {"ã“ã‚Œã¯æ¼¢å­—ã§ã™ã€‚", "\x82\xb1\x82\xea\x82\xcd\x8a\xbf\x8e\x9a\x82\xc5\x82\xb7\x81B", "SJIS"}, {"Hello, 世界!", "Hello, \x90\xa2\x8aE!", "SJIS"}, {"イウエオカ", "\xb2\xb3\xb4\xb5\xb6", "SJIS"}, {"ã“ã‚Œã¯æ¼¢å­—ã§ã™ã€‚", "\xa4\xb3\xa4\xec\xa4\u03f4\xc1\xbb\xfa\xa4\u01e4\xb9\xa1\xa3", "EUC-JP"}, {"Hello, 世界!", "Hello, \x1b$B@$3&\x1b(B!", "ISO-2022-JP"}, {"다ìŒê³¼ ê°™ì€ ì¡°ê±´ì„ ë”°ë¼ì•¼ 합니다: 저작ìží‘œì‹œ", "\xb4\xd9\xc0\xbd\xb0\xfa \xb0\xb0\xc0\xba \xc1\xb6\xb0\xc7\xc0\xbb \xb5\xfb\xb6\xf3\xbe\xdf \xc7Õ´Ï´\xd9: \xc0\xfa\xc0\xdb\xc0\xdaÇ¥\xbd\xc3", "EUC-KR"}, } func TestDecode(t *testing.T) { testCases := append(testCases, []testCase{ // Replace multi-byte maximum subpart of ill-formed subsequence with // single replacement character (WhatWG requirement). {"Rés\ufffdumé", "Rés\xe1\x80umé", "utf8"}, }...) for _, tc := range testCases { e, _ := Lookup(tc.otherEncoding) if e == nil { t.Errorf("%s: not found", tc.otherEncoding) continue } s, err := transformString(e.NewDecoder(), tc.other) if err != nil { t.Errorf("%s: decode %q: %v", tc.otherEncoding, tc.other, err) continue } if s != tc.utf8 { t.Errorf("%s: got %q, want %q", tc.otherEncoding, s, tc.utf8) } } } func TestEncode(t *testing.T) { testCases := append(testCases, []testCase{ // Use Go-style replacement. {"Rés\xe1\x80umé", "Rés\ufffd\ufffdumé", "utf8"}, // U+0144 LATIN SMALL LETTER N WITH ACUTE not supported by encoding. {"GdaÅ„sk", "Gdańsk", "ISO-8859-11"}, {"\ufffd", "�", "ISO-8859-11"}, {"a\xe1\x80b", "a��b", "ISO-8859-11"}, }...) for _, tc := range testCases { e, _ := Lookup(tc.otherEncoding) if e == nil { t.Errorf("%s: not found", tc.otherEncoding) continue } s, err := transformString(e.NewEncoder(), tc.utf8) if err != nil { t.Errorf("%s: encode %q: %s", tc.otherEncoding, tc.utf8, err) continue } if s != tc.other { t.Errorf("%s: got %q, want %q", tc.otherEncoding, s, tc.other) } } } var sniffTestCases = []struct { filename, declared, want string }{ {"HTTP-charset.html", "text/html; charset=iso-8859-15", "iso-8859-15"}, {"UTF-16LE-BOM.html", "", "utf-16le"}, {"UTF-16BE-BOM.html", "", "utf-16be"}, {"meta-content-attribute.html", "text/html", "iso-8859-15"}, {"meta-charset-attribute.html", "text/html", "iso-8859-15"}, {"No-encoding-declaration.html", "text/html", "utf-8"}, {"HTTP-vs-UTF-8-BOM.html", "text/html; charset=iso-8859-15", "utf-8"}, {"HTTP-vs-meta-content.html", "text/html; charset=iso-8859-15", "iso-8859-15"}, {"HTTP-vs-meta-charset.html", "text/html; charset=iso-8859-15", "iso-8859-15"}, {"UTF-8-BOM-vs-meta-content.html", "text/html", "utf-8"}, {"UTF-8-BOM-vs-meta-charset.html", "text/html", "utf-8"}, } func TestSniff(t *testing.T) { switch runtime.GOOS { case "nacl": // platforms that don't permit direct file system access t.Skipf("not supported on %q", runtime.GOOS) } for _, tc := range sniffTestCases { content, err := ioutil.ReadFile("testdata/" + tc.filename) if err != nil { t.Errorf("%s: error reading file: %v", tc.filename, err) continue } _, name, _ := DetermineEncoding(content, tc.declared) if name != tc.want { t.Errorf("%s: got %q, want %q", tc.filename, name, tc.want) continue } } } func TestReader(t *testing.T) { switch runtime.GOOS { case "nacl": // platforms that don't permit direct file system access t.Skipf("not supported on %q", runtime.GOOS) } for _, tc := range sniffTestCases { content, err := ioutil.ReadFile("testdata/" + tc.filename) if err != nil { t.Errorf("%s: error reading file: %v", tc.filename, err) continue } r, err := NewReader(bytes.NewReader(content), tc.declared) if err != nil { t.Errorf("%s: error creating reader: %v", tc.filename, err) continue } got, err := ioutil.ReadAll(r) if err != nil { t.Errorf("%s: error reading from charset.NewReader: %v", tc.filename, err) continue } e, _ := Lookup(tc.want) want, err := ioutil.ReadAll(transform.NewReader(bytes.NewReader(content), e.NewDecoder())) if err != nil { t.Errorf("%s: error decoding with hard-coded charset name: %v", tc.filename, err) continue } if !bytes.Equal(got, want) { t.Errorf("%s: got %q, want %q", tc.filename, got, want) continue } } } var metaTestCases = []struct { meta, want string }{ {"", ""}, {"text/html", ""}, {"text/html; charset utf-8", ""}, {"text/html; charset=latin-2", "latin-2"}, {"text/html; charset; charset = utf-8", "utf-8"}, {`charset="big5"`, "big5"}, {"charset='shift_jis'", "shift_jis"}, } func TestFromMeta(t *testing.T) { for _, tc := range metaTestCases { got := fromMetaElement(tc.meta) if got != tc.want { t.Errorf("%q: got %q, want %q", tc.meta, got, tc.want) } } } func TestXML(t *testing.T) { const s = "r\xe9sum\xe9" d := xml.NewDecoder(strings.NewReader(s)) d.CharsetReader = NewReaderLabel var a struct { Word string } err := d.Decode(&a) if err != nil { t.Fatalf("Decode: %v", err) } want := "résumé" if a.Word != want { t.Errorf("got %q, want %q", a.Word, want) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/000077500000000000000000000000001264464372400246465ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/HTTP-charset.html000066400000000000000000000050711264464372400277450ustar00rootroot00000000000000 HTTP charset

HTTP charset

 

The character encoding of a page can be set using the HTTP header charset declaration.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

The only character encoding declaration for this HTML file is in the HTTP header, which sets the encoding to ISO 8859-15.

Next test
HTML5

the-input-byte-stream-001
Result summary & related tests
Detailed results for this test
Link to spec

Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • The test is read from a server that supports HTTP.
golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/HTTP-vs-UTF-8-BOM.html000066400000000000000000000054061264464372400301620ustar00rootroot00000000000000 HTTP vs UTF-8 BOM

HTTP vs UTF-8 BOM

 

A character encoding set in the HTTP header has lower precedence than the UTF-8 signature.

The HTTP header attempts to set the character encoding to ISO 8859-15. The page starts with a UTF-8 signature.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

If the test is unsuccessful, the characters  should appear at the top of the page. These represent the bytes that make up the UTF-8 signature when encountered in the ISO 8859-15 encoding.

Next test
HTML5

the-input-byte-stream-034
Result summary & related tests
Detailed results for this test
Link to spec

Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • The test is read from a server that supports HTTP.
golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/HTTP-vs-meta-charset.html000066400000000000000000000053501264464372400313170ustar00rootroot00000000000000 HTTP vs meta charset

HTTP vs meta charset

 

The HTTP header has a higher precedence than an encoding declaration in a meta charset attribute.

The HTTP header attempts to set the character encoding to ISO 8859-15. The page contains an encoding declaration in a meta charset attribute that attempts to set the character encoding to ISO 8859-1.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

Next test
HTML5

the-input-byte-stream-018
Result summary & related tests
Detailed results for this test
Link to spec

Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • The test is read from a server that supports HTTP.
golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/HTTP-vs-meta-content.html000066400000000000000000000054241264464372400313420ustar00rootroot00000000000000 HTTP vs meta content

HTTP vs meta content

 

The HTTP header has a higher precedence than an encoding declaration in a meta content attribute.

The HTTP header attempts to set the character encoding to ISO 8859-15. The page contains an encoding declaration in a meta content attribute that attempts to set the character encoding to ISO 8859-1.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

Next test
HTML5

the-input-byte-stream-016
Result summary & related tests
Detailed results for this test
Link to spec

Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • The test is read from a server that supports HTTP.
golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/No-encoding-declaration.html000066400000000000000000000046151264464372400321650ustar00rootroot00000000000000 No encoding declaration

No encoding declaration

 

A page with no encoding information in HTTP, BOM, XML declaration or meta element will be treated as UTF-8.

The test on this page contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

Next test
HTML5

the-input-byte-stream-015
Result summary & related tests
Detailed results for this test
Link to spec

Assumptions:
  • The test is read from a server that supports HTTP.
golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/README000066400000000000000000000006711264464372400255320ustar00rootroot00000000000000These test cases come from http://www.w3.org/International/tests/repository/html5/the-input-byte-stream/results-basics Distributed under both the W3C Test Suite License (http://www.w3.org/Consortium/Legal/2008/04-testsuite-license) and the W3C 3-clause BSD License (http://www.w3.org/Consortium/Legal/2008/03-bsd-license). To contribute to a W3C Test Suite, see the policies and contribution forms (http://www.w3.org/2004/10/27-testcases). golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/UTF-16BE-BOM.html000066400000000000000000000051561264464372400272470ustar00rootroot00000000000000þÿ<!DOCTYPE html> <html lang="en" > <head> <title>UTF-16BE BOM</title> <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> <link rel='help' href='http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream'> <script src="http://w3c-test.org/resources/testharness.js"></script> <script src="http://w3c-test.org/resources/testharnessreport.js"></script> <meta name='flags' content='http'> <style type='text/css'> .test div { width: 50px; } </style> <link rel="stylesheet" type="text/css" href="encodingtests-15.css"> </head> <body> <div class='test'><div id='box' class='ÃSà ¬Ãa'>&#xA0;</div></div> <!-- Notes: No encoding information is declared in the HTTP header or inside the document, other than in the BOM. The text of a class name in the test contains the following sequence of bytes: 0xC3 0xc0 0x53 0xc1 0xC3 0xc0 0xAC 0xc20 0xC3 0xc0 0x61 0xc1. The external, UTF-8-encoded stylesheet contains a selector with a sequence of characters that will only match the class name in the HTML if the page is read as UTF-16BE. --> <script> test(function () { assert_equals(document.getElementById('box').offsetWidth, 100); }, 'A page with no encoding declarations, but with a UTF-16 little-endian BOM will be recognized as UTF-16.'); </script> <div id=log></div> </body> </html> golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/UTF-16LE-BOM.html000066400000000000000000000051721264464372400272570ustar00rootroot00000000000000ÿþ<!DOCTYPE html> <html lang="en" > <head> <title>UTF-16LE BOM</title> <link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'> <link rel='help' href='http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream'> <script src="http://w3c-test.org/resources/testharness.js"></script> <script src="http://w3c-test.org/resources/testharnessreport.js"></script> <meta name='flags' content='http'> <style type='text/css'> .test div { width: 50px; } </style> <link rel="stylesheet" type="text/css" href="encodingtests-15.css"> </head> <body> <div class='test'><div id='box' class='ÃSì Ãa'>&#xA0;</div></div> <!-- Notes: No encoding information is declared in the HTTP header or inside the document, other than in the BOM. The text of a class name in the test contains the following sequence of bytes: 0xC3 0xc0 0x53 0xc1 0xC3 0xc0 0xAC 0xc20 0xC3 0xc0 0x61 0xc1. The external, UTF-8-encoded stylesheet contains a selector with a sequence of characters that will only match the class name in the HTML if the page is read as UTF-16BE. --> <script> test(function () { assert_equals(document.getElementById('box').offsetWidth, 100); }, 'A page with no encoding declarations, but with a UTF-16 little-endian BOM will be recognized as UTF-16.'); </script> <div id="log"></div> </body> </html> golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html000066400000000000000000000053471264464372400317640ustar00rootroot00000000000000 UTF-8 BOM vs meta charset

UTF-8 BOM vs meta charset

 

A page with a UTF-8 BOM will be recognized as UTF-8 even if the meta charset attribute declares a different encoding.

The page contains an encoding declaration in a meta charset attribute that attempts to set the character encoding to ISO 8859-15, but the file starts with a UTF-8 signature.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

Next test
HTML5

the-input-byte-stream-038
Result summary & related tests
Detailed results for this test
Link to spec

Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • The test is read from a server that supports HTTP.
golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/UTF-8-BOM-vs-meta-content.html000066400000000000000000000053711264464372400320020ustar00rootroot00000000000000 UTF-8 BOM vs meta content

UTF-8 BOM vs meta content

 

A page with a UTF-8 BOM will be recognized as UTF-8 even if the meta content attribute declares a different encoding.

The page contains an encoding declaration in a meta content attribute that attempts to set the character encoding to ISO 8859-15, but the file starts with a UTF-8 signature.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ýäè. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.

Next test
HTML5

the-input-byte-stream-037
Result summary & related tests
Detailed results for this test
Link to spec

Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • The test is read from a server that supports HTTP.
golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/meta-charset-attribute.html000066400000000000000000000052141264464372400321140ustar00rootroot00000000000000 meta charset attribute

meta charset attribute

 

The character encoding of the page can be set by a meta element with charset attribute.

The only character encoding declaration for this HTML file is in the charset attribute of the meta element, which declares the encoding to be ISO 8859-15.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

Next test
HTML5

the-input-byte-stream-009
Result summary & related tests
Detailed results for this test
Link to spec

Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • The test is read from a server that supports HTTP.
golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/charset/testdata/meta-content-attribute.html000066400000000000000000000053311264464372400321350ustar00rootroot00000000000000 meta content attribute

meta content attribute

 

The character encoding of the page can be set by a meta element with http-equiv and content attributes.

The only character encoding declaration for this HTML file is in the content attribute of the meta element, which declares the encoding to be ISO 8859-15.

The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector .test div.ÜÀÚ. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.

Next test
HTML5

the-input-byte-stream-007
Result summary & related tests
Detailed results for this test
Link to spec

Assumptions:
  • The default encoding for the browser you are testing is not set to ISO 8859-15.
  • The test is read from a server that supports HTTP.
golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/const.go000066400000000000000000000044361264464372400230700ustar00rootroot00000000000000// 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 html // Section 12.2.3.2 of the HTML5 specification says "The following elements // have varying levels of special parsing rules". // https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements var isSpecialElementMap = map[string]bool{ "address": true, "applet": true, "area": true, "article": true, "aside": true, "base": true, "basefont": true, "bgsound": true, "blockquote": true, "body": true, "br": true, "button": true, "caption": true, "center": true, "col": true, "colgroup": true, "dd": true, "details": true, "dir": true, "div": true, "dl": true, "dt": true, "embed": true, "fieldset": true, "figcaption": true, "figure": true, "footer": true, "form": true, "frame": true, "frameset": true, "h1": true, "h2": true, "h3": true, "h4": true, "h5": true, "h6": true, "head": true, "header": true, "hgroup": true, "hr": true, "html": true, "iframe": true, "img": true, "input": true, "isindex": true, "li": true, "link": true, "listing": true, "marquee": true, "menu": true, "meta": true, "nav": true, "noembed": true, "noframes": true, "noscript": true, "object": true, "ol": true, "p": true, "param": true, "plaintext": true, "pre": true, "script": true, "section": true, "select": true, "source": true, "style": true, "summary": true, "table": true, "tbody": true, "td": true, "template": true, "textarea": true, "tfoot": true, "th": true, "thead": true, "title": true, "tr": true, "track": true, "ul": true, "wbr": true, "xmp": true, } func isSpecialElement(element *Node) bool { switch element.Namespace { case "", "html": return isSpecialElementMap[element.Data] case "svg": return element.Data == "foreignObject" } return false } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/doc.go000066400000000000000000000064761264464372400225150ustar00rootroot00000000000000// 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 html implements an HTML5-compliant tokenizer and parser. Tokenization is done by creating a Tokenizer for an io.Reader r. It is the caller's responsibility to ensure that r provides UTF-8 encoded HTML. z := html.NewTokenizer(r) Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(), which parses the next token and returns its type, or an error: for { tt := z.Next() if tt == html.ErrorToken { // ... return ... } // Process the current token. } There are two APIs for retrieving the current token. The high-level API is to call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs allow optionally calling Raw after Next but before Token, Text, TagName, or TagAttr. In EBNF notation, the valid call sequence per token is: Next {Raw} [ Token | Text | TagName {TagAttr} ] Token returns an independent data structure that completely describes a token. Entities (such as "<") are unescaped, tag names and attribute keys are lower-cased, and attributes are collected into a []Attribute. For example: for { if z.Next() == html.ErrorToken { // Returning io.EOF indicates success. return z.Err() } emitToken(z.Token()) } The low-level API performs fewer allocations and copies, but the contents of the []byte values returned by Text, TagName and TagAttr may change on the next call to Next. For example, to extract an HTML page's anchor text: depth := 0 for { tt := z.Next() switch tt { case ErrorToken: return z.Err() case TextToken: if depth > 0 { // emitBytes should copy the []byte it receives, // if it doesn't process it immediately. emitBytes(z.Text()) } case StartTagToken, EndTagToken: tn, _ := z.TagName() if len(tn) == 1 && tn[0] == 'a' { if tt == StartTagToken { depth++ } else { depth-- } } } } Parsing is done by calling Parse with an io.Reader, which returns the root of the parse tree (the document element) as a *Node. It is the caller's responsibility to ensure that the Reader provides UTF-8 encoded HTML. For example, to process each anchor node in depth-first order: doc, err := html.Parse(r) if err != nil { // ... } var f func(*html.Node) f = func(n *html.Node) { if n.Type == html.ElementNode && n.Data == "a" { // Do something with n... } for c := n.FirstChild; c != nil; c = c.NextSibling { f(c) } } f(doc) The relevant specifications include: https://html.spec.whatwg.org/multipage/syntax.html and https://html.spec.whatwg.org/multipage/syntax.html#tokenization */ package html // import "golang.org/x/net/html" // The tokenization algorithm implemented by this package is not a line-by-line // transliteration of the relatively verbose state-machine in the WHATWG // specification. A more direct approach is used instead, where the program // counter implies the state, such as whether it is tokenizing a tag or a text // node. Specification compliance is verified by checking expected and actual // outputs over a test suite rather than aiming for algorithmic fidelity. // TODO(nigeltao): Does a DOM API belong in this package or a separate one? // TODO(nigeltao): How does parsing interact with a JavaScript engine? golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/doctype.go000066400000000000000000000114751264464372400234120ustar00rootroot00000000000000// 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 html import ( "strings" ) // parseDoctype parses the data from a DoctypeToken into a name, // public identifier, and system identifier. It returns a Node whose Type // is DoctypeNode, whose Data is the name, and which has attributes // named "system" and "public" for the two identifiers if they were present. // quirks is whether the document should be parsed in "quirks mode". func parseDoctype(s string) (n *Node, quirks bool) { n = &Node{Type: DoctypeNode} // Find the name. space := strings.IndexAny(s, whitespace) if space == -1 { space = len(s) } n.Data = s[:space] // The comparison to "html" is case-sensitive. if n.Data != "html" { quirks = true } n.Data = strings.ToLower(n.Data) s = strings.TrimLeft(s[space:], whitespace) if len(s) < 6 { // It can't start with "PUBLIC" or "SYSTEM". // Ignore the rest of the string. return n, quirks || s != "" } key := strings.ToLower(s[:6]) s = s[6:] for key == "public" || key == "system" { s = strings.TrimLeft(s, whitespace) if s == "" { break } quote := s[0] if quote != '"' && quote != '\'' { break } s = s[1:] q := strings.IndexRune(s, rune(quote)) var id string if q == -1 { id = s s = "" } else { id = s[:q] s = s[q+1:] } n.Attr = append(n.Attr, Attribute{Key: key, Val: id}) if key == "public" { key = "system" } else { key = "" } } if key != "" || s != "" { quirks = true } else if len(n.Attr) > 0 { if n.Attr[0].Key == "public" { public := strings.ToLower(n.Attr[0].Val) switch public { case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html": quirks = true default: for _, q := range quirkyIDs { if strings.HasPrefix(public, q) { quirks = true break } } } // The following two public IDs only cause quirks mode if there is no system ID. if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") || strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) { quirks = true } } if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" && strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" { quirks = true } } return n, quirks } // quirkyIDs is a list of public doctype identifiers that cause a document // to be interpreted in quirks mode. The identifiers should be in lower case. var quirkyIDs = []string{ "+//silmaril//dtd html pro v0r11 19970101//", "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", "-//as//dtd html 3.0 aswedit + extensions//", "-//ietf//dtd html 2.0 level 1//", "-//ietf//dtd html 2.0 level 2//", "-//ietf//dtd html 2.0 strict level 1//", "-//ietf//dtd html 2.0 strict level 2//", "-//ietf//dtd html 2.0 strict//", "-//ietf//dtd html 2.0//", "-//ietf//dtd html 2.1e//", "-//ietf//dtd html 3.0//", "-//ietf//dtd html 3.2 final//", "-//ietf//dtd html 3.2//", "-//ietf//dtd html 3//", "-//ietf//dtd html level 0//", "-//ietf//dtd html level 1//", "-//ietf//dtd html level 2//", "-//ietf//dtd html level 3//", "-//ietf//dtd html strict level 0//", "-//ietf//dtd html strict level 1//", "-//ietf//dtd html strict level 2//", "-//ietf//dtd html strict level 3//", "-//ietf//dtd html strict//", "-//ietf//dtd html//", "-//metrius//dtd metrius presentational//", "-//microsoft//dtd internet explorer 2.0 html strict//", "-//microsoft//dtd internet explorer 2.0 html//", "-//microsoft//dtd internet explorer 2.0 tables//", "-//microsoft//dtd internet explorer 3.0 html strict//", "-//microsoft//dtd internet explorer 3.0 html//", "-//microsoft//dtd internet explorer 3.0 tables//", "-//netscape comm. corp.//dtd html//", "-//netscape comm. corp.//dtd strict html//", "-//o'reilly and associates//dtd html 2.0//", "-//o'reilly and associates//dtd html extended 1.0//", "-//o'reilly and associates//dtd html extended relaxed 1.0//", "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", "-//spyglass//dtd html 2.0 extended//", "-//sq//dtd html 2.0 hotmetal + extensions//", "-//sun microsystems corp.//dtd hotjava html//", "-//sun microsystems corp.//dtd hotjava strict html//", "-//w3c//dtd html 3 1995-03-24//", "-//w3c//dtd html 3.2 draft//", "-//w3c//dtd html 3.2 final//", "-//w3c//dtd html 3.2//", "-//w3c//dtd html 3.2s draft//", "-//w3c//dtd html 4.0 frameset//", "-//w3c//dtd html 4.0 transitional//", "-//w3c//dtd html experimental 19960712//", "-//w3c//dtd html experimental 970421//", "-//w3c//dtd w3 html//", "-//w3o//dtd w3 html 3.0//", "-//webtechs//dtd mozilla html 2.0//", "-//webtechs//dtd mozilla html//", } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/entity.go000066400000000000000000003033271264464372400232570ustar00rootroot00000000000000// 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 html // All entities that do not end with ';' are 6 or fewer bytes long. const longestEntityWithoutSemicolon = 6 // entity is a map from HTML entity names to their values. The semicolon matters: // https://html.spec.whatwg.org/multipage/syntax.html#named-character-references // lists both "amp" and "amp;" as two separate entries. // // Note that the HTML5 list is larger than the HTML4 list at // http://www.w3.org/TR/html4/sgml/entities.html var entity = map[string]rune{ "AElig;": '\U000000C6', "AMP;": '\U00000026', "Aacute;": '\U000000C1', "Abreve;": '\U00000102', "Acirc;": '\U000000C2', "Acy;": '\U00000410', "Afr;": '\U0001D504', "Agrave;": '\U000000C0', "Alpha;": '\U00000391', "Amacr;": '\U00000100', "And;": '\U00002A53', "Aogon;": '\U00000104', "Aopf;": '\U0001D538', "ApplyFunction;": '\U00002061', "Aring;": '\U000000C5', "Ascr;": '\U0001D49C', "Assign;": '\U00002254', "Atilde;": '\U000000C3', "Auml;": '\U000000C4', "Backslash;": '\U00002216', "Barv;": '\U00002AE7', "Barwed;": '\U00002306', "Bcy;": '\U00000411', "Because;": '\U00002235', "Bernoullis;": '\U0000212C', "Beta;": '\U00000392', "Bfr;": '\U0001D505', "Bopf;": '\U0001D539', "Breve;": '\U000002D8', "Bscr;": '\U0000212C', "Bumpeq;": '\U0000224E', "CHcy;": '\U00000427', "COPY;": '\U000000A9', "Cacute;": '\U00000106', "Cap;": '\U000022D2', "CapitalDifferentialD;": '\U00002145', "Cayleys;": '\U0000212D', "Ccaron;": '\U0000010C', "Ccedil;": '\U000000C7', "Ccirc;": '\U00000108', "Cconint;": '\U00002230', "Cdot;": '\U0000010A', "Cedilla;": '\U000000B8', "CenterDot;": '\U000000B7', "Cfr;": '\U0000212D', "Chi;": '\U000003A7', "CircleDot;": '\U00002299', "CircleMinus;": '\U00002296', "CirclePlus;": '\U00002295', "CircleTimes;": '\U00002297', "ClockwiseContourIntegral;": '\U00002232', "CloseCurlyDoubleQuote;": '\U0000201D', "CloseCurlyQuote;": '\U00002019', "Colon;": '\U00002237', "Colone;": '\U00002A74', "Congruent;": '\U00002261', "Conint;": '\U0000222F', "ContourIntegral;": '\U0000222E', "Copf;": '\U00002102', "Coproduct;": '\U00002210', "CounterClockwiseContourIntegral;": '\U00002233', "Cross;": '\U00002A2F', "Cscr;": '\U0001D49E', "Cup;": '\U000022D3', "CupCap;": '\U0000224D', "DD;": '\U00002145', "DDotrahd;": '\U00002911', "DJcy;": '\U00000402', "DScy;": '\U00000405', "DZcy;": '\U0000040F', "Dagger;": '\U00002021', "Darr;": '\U000021A1', "Dashv;": '\U00002AE4', "Dcaron;": '\U0000010E', "Dcy;": '\U00000414', "Del;": '\U00002207', "Delta;": '\U00000394', "Dfr;": '\U0001D507', "DiacriticalAcute;": '\U000000B4', "DiacriticalDot;": '\U000002D9', "DiacriticalDoubleAcute;": '\U000002DD', "DiacriticalGrave;": '\U00000060', "DiacriticalTilde;": '\U000002DC', "Diamond;": '\U000022C4', "DifferentialD;": '\U00002146', "Dopf;": '\U0001D53B', "Dot;": '\U000000A8', "DotDot;": '\U000020DC', "DotEqual;": '\U00002250', "DoubleContourIntegral;": '\U0000222F', "DoubleDot;": '\U000000A8', "DoubleDownArrow;": '\U000021D3', "DoubleLeftArrow;": '\U000021D0', "DoubleLeftRightArrow;": '\U000021D4', "DoubleLeftTee;": '\U00002AE4', "DoubleLongLeftArrow;": '\U000027F8', "DoubleLongLeftRightArrow;": '\U000027FA', "DoubleLongRightArrow;": '\U000027F9', "DoubleRightArrow;": '\U000021D2', "DoubleRightTee;": '\U000022A8', "DoubleUpArrow;": '\U000021D1', "DoubleUpDownArrow;": '\U000021D5', "DoubleVerticalBar;": '\U00002225', "DownArrow;": '\U00002193', "DownArrowBar;": '\U00002913', "DownArrowUpArrow;": '\U000021F5', "DownBreve;": '\U00000311', "DownLeftRightVector;": '\U00002950', "DownLeftTeeVector;": '\U0000295E', "DownLeftVector;": '\U000021BD', "DownLeftVectorBar;": '\U00002956', "DownRightTeeVector;": '\U0000295F', "DownRightVector;": '\U000021C1', "DownRightVectorBar;": '\U00002957', "DownTee;": '\U000022A4', "DownTeeArrow;": '\U000021A7', "Downarrow;": '\U000021D3', "Dscr;": '\U0001D49F', "Dstrok;": '\U00000110', "ENG;": '\U0000014A', "ETH;": '\U000000D0', "Eacute;": '\U000000C9', "Ecaron;": '\U0000011A', "Ecirc;": '\U000000CA', "Ecy;": '\U0000042D', "Edot;": '\U00000116', "Efr;": '\U0001D508', "Egrave;": '\U000000C8', "Element;": '\U00002208', "Emacr;": '\U00000112', "EmptySmallSquare;": '\U000025FB', "EmptyVerySmallSquare;": '\U000025AB', "Eogon;": '\U00000118', "Eopf;": '\U0001D53C', "Epsilon;": '\U00000395', "Equal;": '\U00002A75', "EqualTilde;": '\U00002242', "Equilibrium;": '\U000021CC', "Escr;": '\U00002130', "Esim;": '\U00002A73', "Eta;": '\U00000397', "Euml;": '\U000000CB', "Exists;": '\U00002203', "ExponentialE;": '\U00002147', "Fcy;": '\U00000424', "Ffr;": '\U0001D509', "FilledSmallSquare;": '\U000025FC', "FilledVerySmallSquare;": '\U000025AA', "Fopf;": '\U0001D53D', "ForAll;": '\U00002200', "Fouriertrf;": '\U00002131', "Fscr;": '\U00002131', "GJcy;": '\U00000403', "GT;": '\U0000003E', "Gamma;": '\U00000393', "Gammad;": '\U000003DC', "Gbreve;": '\U0000011E', "Gcedil;": '\U00000122', "Gcirc;": '\U0000011C', "Gcy;": '\U00000413', "Gdot;": '\U00000120', "Gfr;": '\U0001D50A', "Gg;": '\U000022D9', "Gopf;": '\U0001D53E', "GreaterEqual;": '\U00002265', "GreaterEqualLess;": '\U000022DB', "GreaterFullEqual;": '\U00002267', "GreaterGreater;": '\U00002AA2', "GreaterLess;": '\U00002277', "GreaterSlantEqual;": '\U00002A7E', "GreaterTilde;": '\U00002273', "Gscr;": '\U0001D4A2', "Gt;": '\U0000226B', "HARDcy;": '\U0000042A', "Hacek;": '\U000002C7', "Hat;": '\U0000005E', "Hcirc;": '\U00000124', "Hfr;": '\U0000210C', "HilbertSpace;": '\U0000210B', "Hopf;": '\U0000210D', "HorizontalLine;": '\U00002500', "Hscr;": '\U0000210B', "Hstrok;": '\U00000126', "HumpDownHump;": '\U0000224E', "HumpEqual;": '\U0000224F', "IEcy;": '\U00000415', "IJlig;": '\U00000132', "IOcy;": '\U00000401', "Iacute;": '\U000000CD', "Icirc;": '\U000000CE', "Icy;": '\U00000418', "Idot;": '\U00000130', "Ifr;": '\U00002111', "Igrave;": '\U000000CC', "Im;": '\U00002111', "Imacr;": '\U0000012A', "ImaginaryI;": '\U00002148', "Implies;": '\U000021D2', "Int;": '\U0000222C', "Integral;": '\U0000222B', "Intersection;": '\U000022C2', "InvisibleComma;": '\U00002063', "InvisibleTimes;": '\U00002062', "Iogon;": '\U0000012E', "Iopf;": '\U0001D540', "Iota;": '\U00000399', "Iscr;": '\U00002110', "Itilde;": '\U00000128', "Iukcy;": '\U00000406', "Iuml;": '\U000000CF', "Jcirc;": '\U00000134', "Jcy;": '\U00000419', "Jfr;": '\U0001D50D', "Jopf;": '\U0001D541', "Jscr;": '\U0001D4A5', "Jsercy;": '\U00000408', "Jukcy;": '\U00000404', "KHcy;": '\U00000425', "KJcy;": '\U0000040C', "Kappa;": '\U0000039A', "Kcedil;": '\U00000136', "Kcy;": '\U0000041A', "Kfr;": '\U0001D50E', "Kopf;": '\U0001D542', "Kscr;": '\U0001D4A6', "LJcy;": '\U00000409', "LT;": '\U0000003C', "Lacute;": '\U00000139', "Lambda;": '\U0000039B', "Lang;": '\U000027EA', "Laplacetrf;": '\U00002112', "Larr;": '\U0000219E', "Lcaron;": '\U0000013D', "Lcedil;": '\U0000013B', "Lcy;": '\U0000041B', "LeftAngleBracket;": '\U000027E8', "LeftArrow;": '\U00002190', "LeftArrowBar;": '\U000021E4', "LeftArrowRightArrow;": '\U000021C6', "LeftCeiling;": '\U00002308', "LeftDoubleBracket;": '\U000027E6', "LeftDownTeeVector;": '\U00002961', "LeftDownVector;": '\U000021C3', "LeftDownVectorBar;": '\U00002959', "LeftFloor;": '\U0000230A', "LeftRightArrow;": '\U00002194', "LeftRightVector;": '\U0000294E', "LeftTee;": '\U000022A3', "LeftTeeArrow;": '\U000021A4', "LeftTeeVector;": '\U0000295A', "LeftTriangle;": '\U000022B2', "LeftTriangleBar;": '\U000029CF', "LeftTriangleEqual;": '\U000022B4', "LeftUpDownVector;": '\U00002951', "LeftUpTeeVector;": '\U00002960', "LeftUpVector;": '\U000021BF', "LeftUpVectorBar;": '\U00002958', "LeftVector;": '\U000021BC', "LeftVectorBar;": '\U00002952', "Leftarrow;": '\U000021D0', "Leftrightarrow;": '\U000021D4', "LessEqualGreater;": '\U000022DA', "LessFullEqual;": '\U00002266', "LessGreater;": '\U00002276', "LessLess;": '\U00002AA1', "LessSlantEqual;": '\U00002A7D', "LessTilde;": '\U00002272', "Lfr;": '\U0001D50F', "Ll;": '\U000022D8', "Lleftarrow;": '\U000021DA', "Lmidot;": '\U0000013F', "LongLeftArrow;": '\U000027F5', "LongLeftRightArrow;": '\U000027F7', "LongRightArrow;": '\U000027F6', "Longleftarrow;": '\U000027F8', "Longleftrightarrow;": '\U000027FA', "Longrightarrow;": '\U000027F9', "Lopf;": '\U0001D543', "LowerLeftArrow;": '\U00002199', "LowerRightArrow;": '\U00002198', "Lscr;": '\U00002112', "Lsh;": '\U000021B0', "Lstrok;": '\U00000141', "Lt;": '\U0000226A', "Map;": '\U00002905', "Mcy;": '\U0000041C', "MediumSpace;": '\U0000205F', "Mellintrf;": '\U00002133', "Mfr;": '\U0001D510', "MinusPlus;": '\U00002213', "Mopf;": '\U0001D544', "Mscr;": '\U00002133', "Mu;": '\U0000039C', "NJcy;": '\U0000040A', "Nacute;": '\U00000143', "Ncaron;": '\U00000147', "Ncedil;": '\U00000145', "Ncy;": '\U0000041D', "NegativeMediumSpace;": '\U0000200B', "NegativeThickSpace;": '\U0000200B', "NegativeThinSpace;": '\U0000200B', "NegativeVeryThinSpace;": '\U0000200B', "NestedGreaterGreater;": '\U0000226B', "NestedLessLess;": '\U0000226A', "NewLine;": '\U0000000A', "Nfr;": '\U0001D511', "NoBreak;": '\U00002060', "NonBreakingSpace;": '\U000000A0', "Nopf;": '\U00002115', "Not;": '\U00002AEC', "NotCongruent;": '\U00002262', "NotCupCap;": '\U0000226D', "NotDoubleVerticalBar;": '\U00002226', "NotElement;": '\U00002209', "NotEqual;": '\U00002260', "NotExists;": '\U00002204', "NotGreater;": '\U0000226F', "NotGreaterEqual;": '\U00002271', "NotGreaterLess;": '\U00002279', "NotGreaterTilde;": '\U00002275', "NotLeftTriangle;": '\U000022EA', "NotLeftTriangleEqual;": '\U000022EC', "NotLess;": '\U0000226E', "NotLessEqual;": '\U00002270', "NotLessGreater;": '\U00002278', "NotLessTilde;": '\U00002274', "NotPrecedes;": '\U00002280', "NotPrecedesSlantEqual;": '\U000022E0', "NotReverseElement;": '\U0000220C', "NotRightTriangle;": '\U000022EB', "NotRightTriangleEqual;": '\U000022ED', "NotSquareSubsetEqual;": '\U000022E2', "NotSquareSupersetEqual;": '\U000022E3', "NotSubsetEqual;": '\U00002288', "NotSucceeds;": '\U00002281', "NotSucceedsSlantEqual;": '\U000022E1', "NotSupersetEqual;": '\U00002289', "NotTilde;": '\U00002241', "NotTildeEqual;": '\U00002244', "NotTildeFullEqual;": '\U00002247', "NotTildeTilde;": '\U00002249', "NotVerticalBar;": '\U00002224', "Nscr;": '\U0001D4A9', "Ntilde;": '\U000000D1', "Nu;": '\U0000039D', "OElig;": '\U00000152', "Oacute;": '\U000000D3', "Ocirc;": '\U000000D4', "Ocy;": '\U0000041E', "Odblac;": '\U00000150', "Ofr;": '\U0001D512', "Ograve;": '\U000000D2', "Omacr;": '\U0000014C', "Omega;": '\U000003A9', "Omicron;": '\U0000039F', "Oopf;": '\U0001D546', "OpenCurlyDoubleQuote;": '\U0000201C', "OpenCurlyQuote;": '\U00002018', "Or;": '\U00002A54', "Oscr;": '\U0001D4AA', "Oslash;": '\U000000D8', "Otilde;": '\U000000D5', "Otimes;": '\U00002A37', "Ouml;": '\U000000D6', "OverBar;": '\U0000203E', "OverBrace;": '\U000023DE', "OverBracket;": '\U000023B4', "OverParenthesis;": '\U000023DC', "PartialD;": '\U00002202', "Pcy;": '\U0000041F', "Pfr;": '\U0001D513', "Phi;": '\U000003A6', "Pi;": '\U000003A0', "PlusMinus;": '\U000000B1', "Poincareplane;": '\U0000210C', "Popf;": '\U00002119', "Pr;": '\U00002ABB', "Precedes;": '\U0000227A', "PrecedesEqual;": '\U00002AAF', "PrecedesSlantEqual;": '\U0000227C', "PrecedesTilde;": '\U0000227E', "Prime;": '\U00002033', "Product;": '\U0000220F', "Proportion;": '\U00002237', "Proportional;": '\U0000221D', "Pscr;": '\U0001D4AB', "Psi;": '\U000003A8', "QUOT;": '\U00000022', "Qfr;": '\U0001D514', "Qopf;": '\U0000211A', "Qscr;": '\U0001D4AC', "RBarr;": '\U00002910', "REG;": '\U000000AE', "Racute;": '\U00000154', "Rang;": '\U000027EB', "Rarr;": '\U000021A0', "Rarrtl;": '\U00002916', "Rcaron;": '\U00000158', "Rcedil;": '\U00000156', "Rcy;": '\U00000420', "Re;": '\U0000211C', "ReverseElement;": '\U0000220B', "ReverseEquilibrium;": '\U000021CB', "ReverseUpEquilibrium;": '\U0000296F', "Rfr;": '\U0000211C', "Rho;": '\U000003A1', "RightAngleBracket;": '\U000027E9', "RightArrow;": '\U00002192', "RightArrowBar;": '\U000021E5', "RightArrowLeftArrow;": '\U000021C4', "RightCeiling;": '\U00002309', "RightDoubleBracket;": '\U000027E7', "RightDownTeeVector;": '\U0000295D', "RightDownVector;": '\U000021C2', "RightDownVectorBar;": '\U00002955', "RightFloor;": '\U0000230B', "RightTee;": '\U000022A2', "RightTeeArrow;": '\U000021A6', "RightTeeVector;": '\U0000295B', "RightTriangle;": '\U000022B3', "RightTriangleBar;": '\U000029D0', "RightTriangleEqual;": '\U000022B5', "RightUpDownVector;": '\U0000294F', "RightUpTeeVector;": '\U0000295C', "RightUpVector;": '\U000021BE', "RightUpVectorBar;": '\U00002954', "RightVector;": '\U000021C0', "RightVectorBar;": '\U00002953', "Rightarrow;": '\U000021D2', "Ropf;": '\U0000211D', "RoundImplies;": '\U00002970', "Rrightarrow;": '\U000021DB', "Rscr;": '\U0000211B', "Rsh;": '\U000021B1', "RuleDelayed;": '\U000029F4', "SHCHcy;": '\U00000429', "SHcy;": '\U00000428', "SOFTcy;": '\U0000042C', "Sacute;": '\U0000015A', "Sc;": '\U00002ABC', "Scaron;": '\U00000160', "Scedil;": '\U0000015E', "Scirc;": '\U0000015C', "Scy;": '\U00000421', "Sfr;": '\U0001D516', "ShortDownArrow;": '\U00002193', "ShortLeftArrow;": '\U00002190', "ShortRightArrow;": '\U00002192', "ShortUpArrow;": '\U00002191', "Sigma;": '\U000003A3', "SmallCircle;": '\U00002218', "Sopf;": '\U0001D54A', "Sqrt;": '\U0000221A', "Square;": '\U000025A1', "SquareIntersection;": '\U00002293', "SquareSubset;": '\U0000228F', "SquareSubsetEqual;": '\U00002291', "SquareSuperset;": '\U00002290', "SquareSupersetEqual;": '\U00002292', "SquareUnion;": '\U00002294', "Sscr;": '\U0001D4AE', "Star;": '\U000022C6', "Sub;": '\U000022D0', "Subset;": '\U000022D0', "SubsetEqual;": '\U00002286', "Succeeds;": '\U0000227B', "SucceedsEqual;": '\U00002AB0', "SucceedsSlantEqual;": '\U0000227D', "SucceedsTilde;": '\U0000227F', "SuchThat;": '\U0000220B', "Sum;": '\U00002211', "Sup;": '\U000022D1', "Superset;": '\U00002283', "SupersetEqual;": '\U00002287', "Supset;": '\U000022D1', "THORN;": '\U000000DE', "TRADE;": '\U00002122', "TSHcy;": '\U0000040B', "TScy;": '\U00000426', "Tab;": '\U00000009', "Tau;": '\U000003A4', "Tcaron;": '\U00000164', "Tcedil;": '\U00000162', "Tcy;": '\U00000422', "Tfr;": '\U0001D517', "Therefore;": '\U00002234', "Theta;": '\U00000398', "ThinSpace;": '\U00002009', "Tilde;": '\U0000223C', "TildeEqual;": '\U00002243', "TildeFullEqual;": '\U00002245', "TildeTilde;": '\U00002248', "Topf;": '\U0001D54B', "TripleDot;": '\U000020DB', "Tscr;": '\U0001D4AF', "Tstrok;": '\U00000166', "Uacute;": '\U000000DA', "Uarr;": '\U0000219F', "Uarrocir;": '\U00002949', "Ubrcy;": '\U0000040E', "Ubreve;": '\U0000016C', "Ucirc;": '\U000000DB', "Ucy;": '\U00000423', "Udblac;": '\U00000170', "Ufr;": '\U0001D518', "Ugrave;": '\U000000D9', "Umacr;": '\U0000016A', "UnderBar;": '\U0000005F', "UnderBrace;": '\U000023DF', "UnderBracket;": '\U000023B5', "UnderParenthesis;": '\U000023DD', "Union;": '\U000022C3', "UnionPlus;": '\U0000228E', "Uogon;": '\U00000172', "Uopf;": '\U0001D54C', "UpArrow;": '\U00002191', "UpArrowBar;": '\U00002912', "UpArrowDownArrow;": '\U000021C5', "UpDownArrow;": '\U00002195', "UpEquilibrium;": '\U0000296E', "UpTee;": '\U000022A5', "UpTeeArrow;": '\U000021A5', "Uparrow;": '\U000021D1', "Updownarrow;": '\U000021D5', "UpperLeftArrow;": '\U00002196', "UpperRightArrow;": '\U00002197', "Upsi;": '\U000003D2', "Upsilon;": '\U000003A5', "Uring;": '\U0000016E', "Uscr;": '\U0001D4B0', "Utilde;": '\U00000168', "Uuml;": '\U000000DC', "VDash;": '\U000022AB', "Vbar;": '\U00002AEB', "Vcy;": '\U00000412', "Vdash;": '\U000022A9', "Vdashl;": '\U00002AE6', "Vee;": '\U000022C1', "Verbar;": '\U00002016', "Vert;": '\U00002016', "VerticalBar;": '\U00002223', "VerticalLine;": '\U0000007C', "VerticalSeparator;": '\U00002758', "VerticalTilde;": '\U00002240', "VeryThinSpace;": '\U0000200A', "Vfr;": '\U0001D519', "Vopf;": '\U0001D54D', "Vscr;": '\U0001D4B1', "Vvdash;": '\U000022AA', "Wcirc;": '\U00000174', "Wedge;": '\U000022C0', "Wfr;": '\U0001D51A', "Wopf;": '\U0001D54E', "Wscr;": '\U0001D4B2', "Xfr;": '\U0001D51B', "Xi;": '\U0000039E', "Xopf;": '\U0001D54F', "Xscr;": '\U0001D4B3', "YAcy;": '\U0000042F', "YIcy;": '\U00000407', "YUcy;": '\U0000042E', "Yacute;": '\U000000DD', "Ycirc;": '\U00000176', "Ycy;": '\U0000042B', "Yfr;": '\U0001D51C', "Yopf;": '\U0001D550', "Yscr;": '\U0001D4B4', "Yuml;": '\U00000178', "ZHcy;": '\U00000416', "Zacute;": '\U00000179', "Zcaron;": '\U0000017D', "Zcy;": '\U00000417', "Zdot;": '\U0000017B', "ZeroWidthSpace;": '\U0000200B', "Zeta;": '\U00000396', "Zfr;": '\U00002128', "Zopf;": '\U00002124', "Zscr;": '\U0001D4B5', "aacute;": '\U000000E1', "abreve;": '\U00000103', "ac;": '\U0000223E', "acd;": '\U0000223F', "acirc;": '\U000000E2', "acute;": '\U000000B4', "acy;": '\U00000430', "aelig;": '\U000000E6', "af;": '\U00002061', "afr;": '\U0001D51E', "agrave;": '\U000000E0', "alefsym;": '\U00002135', "aleph;": '\U00002135', "alpha;": '\U000003B1', "amacr;": '\U00000101', "amalg;": '\U00002A3F', "amp;": '\U00000026', "and;": '\U00002227', "andand;": '\U00002A55', "andd;": '\U00002A5C', "andslope;": '\U00002A58', "andv;": '\U00002A5A', "ang;": '\U00002220', "ange;": '\U000029A4', "angle;": '\U00002220', "angmsd;": '\U00002221', "angmsdaa;": '\U000029A8', "angmsdab;": '\U000029A9', "angmsdac;": '\U000029AA', "angmsdad;": '\U000029AB', "angmsdae;": '\U000029AC', "angmsdaf;": '\U000029AD', "angmsdag;": '\U000029AE', "angmsdah;": '\U000029AF', "angrt;": '\U0000221F', "angrtvb;": '\U000022BE', "angrtvbd;": '\U0000299D', "angsph;": '\U00002222', "angst;": '\U000000C5', "angzarr;": '\U0000237C', "aogon;": '\U00000105', "aopf;": '\U0001D552', "ap;": '\U00002248', "apE;": '\U00002A70', "apacir;": '\U00002A6F', "ape;": '\U0000224A', "apid;": '\U0000224B', "apos;": '\U00000027', "approx;": '\U00002248', "approxeq;": '\U0000224A', "aring;": '\U000000E5', "ascr;": '\U0001D4B6', "ast;": '\U0000002A', "asymp;": '\U00002248', "asympeq;": '\U0000224D', "atilde;": '\U000000E3', "auml;": '\U000000E4', "awconint;": '\U00002233', "awint;": '\U00002A11', "bNot;": '\U00002AED', "backcong;": '\U0000224C', "backepsilon;": '\U000003F6', "backprime;": '\U00002035', "backsim;": '\U0000223D', "backsimeq;": '\U000022CD', "barvee;": '\U000022BD', "barwed;": '\U00002305', "barwedge;": '\U00002305', "bbrk;": '\U000023B5', "bbrktbrk;": '\U000023B6', "bcong;": '\U0000224C', "bcy;": '\U00000431', "bdquo;": '\U0000201E', "becaus;": '\U00002235', "because;": '\U00002235', "bemptyv;": '\U000029B0', "bepsi;": '\U000003F6', "bernou;": '\U0000212C', "beta;": '\U000003B2', "beth;": '\U00002136', "between;": '\U0000226C', "bfr;": '\U0001D51F', "bigcap;": '\U000022C2', "bigcirc;": '\U000025EF', "bigcup;": '\U000022C3', "bigodot;": '\U00002A00', "bigoplus;": '\U00002A01', "bigotimes;": '\U00002A02', "bigsqcup;": '\U00002A06', "bigstar;": '\U00002605', "bigtriangledown;": '\U000025BD', "bigtriangleup;": '\U000025B3', "biguplus;": '\U00002A04', "bigvee;": '\U000022C1', "bigwedge;": '\U000022C0', "bkarow;": '\U0000290D', "blacklozenge;": '\U000029EB', "blacksquare;": '\U000025AA', "blacktriangle;": '\U000025B4', "blacktriangledown;": '\U000025BE', "blacktriangleleft;": '\U000025C2', "blacktriangleright;": '\U000025B8', "blank;": '\U00002423', "blk12;": '\U00002592', "blk14;": '\U00002591', "blk34;": '\U00002593', "block;": '\U00002588', "bnot;": '\U00002310', "bopf;": '\U0001D553', "bot;": '\U000022A5', "bottom;": '\U000022A5', "bowtie;": '\U000022C8', "boxDL;": '\U00002557', "boxDR;": '\U00002554', "boxDl;": '\U00002556', "boxDr;": '\U00002553', "boxH;": '\U00002550', "boxHD;": '\U00002566', "boxHU;": '\U00002569', "boxHd;": '\U00002564', "boxHu;": '\U00002567', "boxUL;": '\U0000255D', "boxUR;": '\U0000255A', "boxUl;": '\U0000255C', "boxUr;": '\U00002559', "boxV;": '\U00002551', "boxVH;": '\U0000256C', "boxVL;": '\U00002563', "boxVR;": '\U00002560', "boxVh;": '\U0000256B', "boxVl;": '\U00002562', "boxVr;": '\U0000255F', "boxbox;": '\U000029C9', "boxdL;": '\U00002555', "boxdR;": '\U00002552', "boxdl;": '\U00002510', "boxdr;": '\U0000250C', "boxh;": '\U00002500', "boxhD;": '\U00002565', "boxhU;": '\U00002568', "boxhd;": '\U0000252C', "boxhu;": '\U00002534', "boxminus;": '\U0000229F', "boxplus;": '\U0000229E', "boxtimes;": '\U000022A0', "boxuL;": '\U0000255B', "boxuR;": '\U00002558', "boxul;": '\U00002518', "boxur;": '\U00002514', "boxv;": '\U00002502', "boxvH;": '\U0000256A', "boxvL;": '\U00002561', "boxvR;": '\U0000255E', "boxvh;": '\U0000253C', "boxvl;": '\U00002524', "boxvr;": '\U0000251C', "bprime;": '\U00002035', "breve;": '\U000002D8', "brvbar;": '\U000000A6', "bscr;": '\U0001D4B7', "bsemi;": '\U0000204F', "bsim;": '\U0000223D', "bsime;": '\U000022CD', "bsol;": '\U0000005C', "bsolb;": '\U000029C5', "bsolhsub;": '\U000027C8', "bull;": '\U00002022', "bullet;": '\U00002022', "bump;": '\U0000224E', "bumpE;": '\U00002AAE', "bumpe;": '\U0000224F', "bumpeq;": '\U0000224F', "cacute;": '\U00000107', "cap;": '\U00002229', "capand;": '\U00002A44', "capbrcup;": '\U00002A49', "capcap;": '\U00002A4B', "capcup;": '\U00002A47', "capdot;": '\U00002A40', "caret;": '\U00002041', "caron;": '\U000002C7', "ccaps;": '\U00002A4D', "ccaron;": '\U0000010D', "ccedil;": '\U000000E7', "ccirc;": '\U00000109', "ccups;": '\U00002A4C', "ccupssm;": '\U00002A50', "cdot;": '\U0000010B', "cedil;": '\U000000B8', "cemptyv;": '\U000029B2', "cent;": '\U000000A2', "centerdot;": '\U000000B7', "cfr;": '\U0001D520', "chcy;": '\U00000447', "check;": '\U00002713', "checkmark;": '\U00002713', "chi;": '\U000003C7', "cir;": '\U000025CB', "cirE;": '\U000029C3', "circ;": '\U000002C6', "circeq;": '\U00002257', "circlearrowleft;": '\U000021BA', "circlearrowright;": '\U000021BB', "circledR;": '\U000000AE', "circledS;": '\U000024C8', "circledast;": '\U0000229B', "circledcirc;": '\U0000229A', "circleddash;": '\U0000229D', "cire;": '\U00002257', "cirfnint;": '\U00002A10', "cirmid;": '\U00002AEF', "cirscir;": '\U000029C2', "clubs;": '\U00002663', "clubsuit;": '\U00002663', "colon;": '\U0000003A', "colone;": '\U00002254', "coloneq;": '\U00002254', "comma;": '\U0000002C', "commat;": '\U00000040', "comp;": '\U00002201', "compfn;": '\U00002218', "complement;": '\U00002201', "complexes;": '\U00002102', "cong;": '\U00002245', "congdot;": '\U00002A6D', "conint;": '\U0000222E', "copf;": '\U0001D554', "coprod;": '\U00002210', "copy;": '\U000000A9', "copysr;": '\U00002117', "crarr;": '\U000021B5', "cross;": '\U00002717', "cscr;": '\U0001D4B8', "csub;": '\U00002ACF', "csube;": '\U00002AD1', "csup;": '\U00002AD0', "csupe;": '\U00002AD2', "ctdot;": '\U000022EF', "cudarrl;": '\U00002938', "cudarrr;": '\U00002935', "cuepr;": '\U000022DE', "cuesc;": '\U000022DF', "cularr;": '\U000021B6', "cularrp;": '\U0000293D', "cup;": '\U0000222A', "cupbrcap;": '\U00002A48', "cupcap;": '\U00002A46', "cupcup;": '\U00002A4A', "cupdot;": '\U0000228D', "cupor;": '\U00002A45', "curarr;": '\U000021B7', "curarrm;": '\U0000293C', "curlyeqprec;": '\U000022DE', "curlyeqsucc;": '\U000022DF', "curlyvee;": '\U000022CE', "curlywedge;": '\U000022CF', "curren;": '\U000000A4', "curvearrowleft;": '\U000021B6', "curvearrowright;": '\U000021B7', "cuvee;": '\U000022CE', "cuwed;": '\U000022CF', "cwconint;": '\U00002232', "cwint;": '\U00002231', "cylcty;": '\U0000232D', "dArr;": '\U000021D3', "dHar;": '\U00002965', "dagger;": '\U00002020', "daleth;": '\U00002138', "darr;": '\U00002193', "dash;": '\U00002010', "dashv;": '\U000022A3', "dbkarow;": '\U0000290F', "dblac;": '\U000002DD', "dcaron;": '\U0000010F', "dcy;": '\U00000434', "dd;": '\U00002146', "ddagger;": '\U00002021', "ddarr;": '\U000021CA', "ddotseq;": '\U00002A77', "deg;": '\U000000B0', "delta;": '\U000003B4', "demptyv;": '\U000029B1', "dfisht;": '\U0000297F', "dfr;": '\U0001D521', "dharl;": '\U000021C3', "dharr;": '\U000021C2', "diam;": '\U000022C4', "diamond;": '\U000022C4', "diamondsuit;": '\U00002666', "diams;": '\U00002666', "die;": '\U000000A8', "digamma;": '\U000003DD', "disin;": '\U000022F2', "div;": '\U000000F7', "divide;": '\U000000F7', "divideontimes;": '\U000022C7', "divonx;": '\U000022C7', "djcy;": '\U00000452', "dlcorn;": '\U0000231E', "dlcrop;": '\U0000230D', "dollar;": '\U00000024', "dopf;": '\U0001D555', "dot;": '\U000002D9', "doteq;": '\U00002250', "doteqdot;": '\U00002251', "dotminus;": '\U00002238', "dotplus;": '\U00002214', "dotsquare;": '\U000022A1', "doublebarwedge;": '\U00002306', "downarrow;": '\U00002193', "downdownarrows;": '\U000021CA', "downharpoonleft;": '\U000021C3', "downharpoonright;": '\U000021C2', "drbkarow;": '\U00002910', "drcorn;": '\U0000231F', "drcrop;": '\U0000230C', "dscr;": '\U0001D4B9', "dscy;": '\U00000455', "dsol;": '\U000029F6', "dstrok;": '\U00000111', "dtdot;": '\U000022F1', "dtri;": '\U000025BF', "dtrif;": '\U000025BE', "duarr;": '\U000021F5', "duhar;": '\U0000296F', "dwangle;": '\U000029A6', "dzcy;": '\U0000045F', "dzigrarr;": '\U000027FF', "eDDot;": '\U00002A77', "eDot;": '\U00002251', "eacute;": '\U000000E9', "easter;": '\U00002A6E', "ecaron;": '\U0000011B', "ecir;": '\U00002256', "ecirc;": '\U000000EA', "ecolon;": '\U00002255', "ecy;": '\U0000044D', "edot;": '\U00000117', "ee;": '\U00002147', "efDot;": '\U00002252', "efr;": '\U0001D522', "eg;": '\U00002A9A', "egrave;": '\U000000E8', "egs;": '\U00002A96', "egsdot;": '\U00002A98', "el;": '\U00002A99', "elinters;": '\U000023E7', "ell;": '\U00002113', "els;": '\U00002A95', "elsdot;": '\U00002A97', "emacr;": '\U00000113', "empty;": '\U00002205', "emptyset;": '\U00002205', "emptyv;": '\U00002205', "emsp;": '\U00002003', "emsp13;": '\U00002004', "emsp14;": '\U00002005', "eng;": '\U0000014B', "ensp;": '\U00002002', "eogon;": '\U00000119', "eopf;": '\U0001D556', "epar;": '\U000022D5', "eparsl;": '\U000029E3', "eplus;": '\U00002A71', "epsi;": '\U000003B5', "epsilon;": '\U000003B5', "epsiv;": '\U000003F5', "eqcirc;": '\U00002256', "eqcolon;": '\U00002255', "eqsim;": '\U00002242', "eqslantgtr;": '\U00002A96', "eqslantless;": '\U00002A95', "equals;": '\U0000003D', "equest;": '\U0000225F', "equiv;": '\U00002261', "equivDD;": '\U00002A78', "eqvparsl;": '\U000029E5', "erDot;": '\U00002253', "erarr;": '\U00002971', "escr;": '\U0000212F', "esdot;": '\U00002250', "esim;": '\U00002242', "eta;": '\U000003B7', "eth;": '\U000000F0', "euml;": '\U000000EB', "euro;": '\U000020AC', "excl;": '\U00000021', "exist;": '\U00002203', "expectation;": '\U00002130', "exponentiale;": '\U00002147', "fallingdotseq;": '\U00002252', "fcy;": '\U00000444', "female;": '\U00002640', "ffilig;": '\U0000FB03', "fflig;": '\U0000FB00', "ffllig;": '\U0000FB04', "ffr;": '\U0001D523', "filig;": '\U0000FB01', "flat;": '\U0000266D', "fllig;": '\U0000FB02', "fltns;": '\U000025B1', "fnof;": '\U00000192', "fopf;": '\U0001D557', "forall;": '\U00002200', "fork;": '\U000022D4', "forkv;": '\U00002AD9', "fpartint;": '\U00002A0D', "frac12;": '\U000000BD', "frac13;": '\U00002153', "frac14;": '\U000000BC', "frac15;": '\U00002155', "frac16;": '\U00002159', "frac18;": '\U0000215B', "frac23;": '\U00002154', "frac25;": '\U00002156', "frac34;": '\U000000BE', "frac35;": '\U00002157', "frac38;": '\U0000215C', "frac45;": '\U00002158', "frac56;": '\U0000215A', "frac58;": '\U0000215D', "frac78;": '\U0000215E', "frasl;": '\U00002044', "frown;": '\U00002322', "fscr;": '\U0001D4BB', "gE;": '\U00002267', "gEl;": '\U00002A8C', "gacute;": '\U000001F5', "gamma;": '\U000003B3', "gammad;": '\U000003DD', "gap;": '\U00002A86', "gbreve;": '\U0000011F', "gcirc;": '\U0000011D', "gcy;": '\U00000433', "gdot;": '\U00000121', "ge;": '\U00002265', "gel;": '\U000022DB', "geq;": '\U00002265', "geqq;": '\U00002267', "geqslant;": '\U00002A7E', "ges;": '\U00002A7E', "gescc;": '\U00002AA9', "gesdot;": '\U00002A80', "gesdoto;": '\U00002A82', "gesdotol;": '\U00002A84', "gesles;": '\U00002A94', "gfr;": '\U0001D524', "gg;": '\U0000226B', "ggg;": '\U000022D9', "gimel;": '\U00002137', "gjcy;": '\U00000453', "gl;": '\U00002277', "glE;": '\U00002A92', "gla;": '\U00002AA5', "glj;": '\U00002AA4', "gnE;": '\U00002269', "gnap;": '\U00002A8A', "gnapprox;": '\U00002A8A', "gne;": '\U00002A88', "gneq;": '\U00002A88', "gneqq;": '\U00002269', "gnsim;": '\U000022E7', "gopf;": '\U0001D558', "grave;": '\U00000060', "gscr;": '\U0000210A', "gsim;": '\U00002273', "gsime;": '\U00002A8E', "gsiml;": '\U00002A90', "gt;": '\U0000003E', "gtcc;": '\U00002AA7', "gtcir;": '\U00002A7A', "gtdot;": '\U000022D7', "gtlPar;": '\U00002995', "gtquest;": '\U00002A7C', "gtrapprox;": '\U00002A86', "gtrarr;": '\U00002978', "gtrdot;": '\U000022D7', "gtreqless;": '\U000022DB', "gtreqqless;": '\U00002A8C', "gtrless;": '\U00002277', "gtrsim;": '\U00002273', "hArr;": '\U000021D4', "hairsp;": '\U0000200A', "half;": '\U000000BD', "hamilt;": '\U0000210B', "hardcy;": '\U0000044A', "harr;": '\U00002194', "harrcir;": '\U00002948', "harrw;": '\U000021AD', "hbar;": '\U0000210F', "hcirc;": '\U00000125', "hearts;": '\U00002665', "heartsuit;": '\U00002665', "hellip;": '\U00002026', "hercon;": '\U000022B9', "hfr;": '\U0001D525', "hksearow;": '\U00002925', "hkswarow;": '\U00002926', "hoarr;": '\U000021FF', "homtht;": '\U0000223B', "hookleftarrow;": '\U000021A9', "hookrightarrow;": '\U000021AA', "hopf;": '\U0001D559', "horbar;": '\U00002015', "hscr;": '\U0001D4BD', "hslash;": '\U0000210F', "hstrok;": '\U00000127', "hybull;": '\U00002043', "hyphen;": '\U00002010', "iacute;": '\U000000ED', "ic;": '\U00002063', "icirc;": '\U000000EE', "icy;": '\U00000438', "iecy;": '\U00000435', "iexcl;": '\U000000A1', "iff;": '\U000021D4', "ifr;": '\U0001D526', "igrave;": '\U000000EC', "ii;": '\U00002148', "iiiint;": '\U00002A0C', "iiint;": '\U0000222D', "iinfin;": '\U000029DC', "iiota;": '\U00002129', "ijlig;": '\U00000133', "imacr;": '\U0000012B', "image;": '\U00002111', "imagline;": '\U00002110', "imagpart;": '\U00002111', "imath;": '\U00000131', "imof;": '\U000022B7', "imped;": '\U000001B5', "in;": '\U00002208', "incare;": '\U00002105', "infin;": '\U0000221E', "infintie;": '\U000029DD', "inodot;": '\U00000131', "int;": '\U0000222B', "intcal;": '\U000022BA', "integers;": '\U00002124', "intercal;": '\U000022BA', "intlarhk;": '\U00002A17', "intprod;": '\U00002A3C', "iocy;": '\U00000451', "iogon;": '\U0000012F', "iopf;": '\U0001D55A', "iota;": '\U000003B9', "iprod;": '\U00002A3C', "iquest;": '\U000000BF', "iscr;": '\U0001D4BE', "isin;": '\U00002208', "isinE;": '\U000022F9', "isindot;": '\U000022F5', "isins;": '\U000022F4', "isinsv;": '\U000022F3', "isinv;": '\U00002208', "it;": '\U00002062', "itilde;": '\U00000129', "iukcy;": '\U00000456', "iuml;": '\U000000EF', "jcirc;": '\U00000135', "jcy;": '\U00000439', "jfr;": '\U0001D527', "jmath;": '\U00000237', "jopf;": '\U0001D55B', "jscr;": '\U0001D4BF', "jsercy;": '\U00000458', "jukcy;": '\U00000454', "kappa;": '\U000003BA', "kappav;": '\U000003F0', "kcedil;": '\U00000137', "kcy;": '\U0000043A', "kfr;": '\U0001D528', "kgreen;": '\U00000138', "khcy;": '\U00000445', "kjcy;": '\U0000045C', "kopf;": '\U0001D55C', "kscr;": '\U0001D4C0', "lAarr;": '\U000021DA', "lArr;": '\U000021D0', "lAtail;": '\U0000291B', "lBarr;": '\U0000290E', "lE;": '\U00002266', "lEg;": '\U00002A8B', "lHar;": '\U00002962', "lacute;": '\U0000013A', "laemptyv;": '\U000029B4', "lagran;": '\U00002112', "lambda;": '\U000003BB', "lang;": '\U000027E8', "langd;": '\U00002991', "langle;": '\U000027E8', "lap;": '\U00002A85', "laquo;": '\U000000AB', "larr;": '\U00002190', "larrb;": '\U000021E4', "larrbfs;": '\U0000291F', "larrfs;": '\U0000291D', "larrhk;": '\U000021A9', "larrlp;": '\U000021AB', "larrpl;": '\U00002939', "larrsim;": '\U00002973', "larrtl;": '\U000021A2', "lat;": '\U00002AAB', "latail;": '\U00002919', "late;": '\U00002AAD', "lbarr;": '\U0000290C', "lbbrk;": '\U00002772', "lbrace;": '\U0000007B', "lbrack;": '\U0000005B', "lbrke;": '\U0000298B', "lbrksld;": '\U0000298F', "lbrkslu;": '\U0000298D', "lcaron;": '\U0000013E', "lcedil;": '\U0000013C', "lceil;": '\U00002308', "lcub;": '\U0000007B', "lcy;": '\U0000043B', "ldca;": '\U00002936', "ldquo;": '\U0000201C', "ldquor;": '\U0000201E', "ldrdhar;": '\U00002967', "ldrushar;": '\U0000294B', "ldsh;": '\U000021B2', "le;": '\U00002264', "leftarrow;": '\U00002190', "leftarrowtail;": '\U000021A2', "leftharpoondown;": '\U000021BD', "leftharpoonup;": '\U000021BC', "leftleftarrows;": '\U000021C7', "leftrightarrow;": '\U00002194', "leftrightarrows;": '\U000021C6', "leftrightharpoons;": '\U000021CB', "leftrightsquigarrow;": '\U000021AD', "leftthreetimes;": '\U000022CB', "leg;": '\U000022DA', "leq;": '\U00002264', "leqq;": '\U00002266', "leqslant;": '\U00002A7D', "les;": '\U00002A7D', "lescc;": '\U00002AA8', "lesdot;": '\U00002A7F', "lesdoto;": '\U00002A81', "lesdotor;": '\U00002A83', "lesges;": '\U00002A93', "lessapprox;": '\U00002A85', "lessdot;": '\U000022D6', "lesseqgtr;": '\U000022DA', "lesseqqgtr;": '\U00002A8B', "lessgtr;": '\U00002276', "lesssim;": '\U00002272', "lfisht;": '\U0000297C', "lfloor;": '\U0000230A', "lfr;": '\U0001D529', "lg;": '\U00002276', "lgE;": '\U00002A91', "lhard;": '\U000021BD', "lharu;": '\U000021BC', "lharul;": '\U0000296A', "lhblk;": '\U00002584', "ljcy;": '\U00000459', "ll;": '\U0000226A', "llarr;": '\U000021C7', "llcorner;": '\U0000231E', "llhard;": '\U0000296B', "lltri;": '\U000025FA', "lmidot;": '\U00000140', "lmoust;": '\U000023B0', "lmoustache;": '\U000023B0', "lnE;": '\U00002268', "lnap;": '\U00002A89', "lnapprox;": '\U00002A89', "lne;": '\U00002A87', "lneq;": '\U00002A87', "lneqq;": '\U00002268', "lnsim;": '\U000022E6', "loang;": '\U000027EC', "loarr;": '\U000021FD', "lobrk;": '\U000027E6', "longleftarrow;": '\U000027F5', "longleftrightarrow;": '\U000027F7', "longmapsto;": '\U000027FC', "longrightarrow;": '\U000027F6', "looparrowleft;": '\U000021AB', "looparrowright;": '\U000021AC', "lopar;": '\U00002985', "lopf;": '\U0001D55D', "loplus;": '\U00002A2D', "lotimes;": '\U00002A34', "lowast;": '\U00002217', "lowbar;": '\U0000005F', "loz;": '\U000025CA', "lozenge;": '\U000025CA', "lozf;": '\U000029EB', "lpar;": '\U00000028', "lparlt;": '\U00002993', "lrarr;": '\U000021C6', "lrcorner;": '\U0000231F', "lrhar;": '\U000021CB', "lrhard;": '\U0000296D', "lrm;": '\U0000200E', "lrtri;": '\U000022BF', "lsaquo;": '\U00002039', "lscr;": '\U0001D4C1', "lsh;": '\U000021B0', "lsim;": '\U00002272', "lsime;": '\U00002A8D', "lsimg;": '\U00002A8F', "lsqb;": '\U0000005B', "lsquo;": '\U00002018', "lsquor;": '\U0000201A', "lstrok;": '\U00000142', "lt;": '\U0000003C', "ltcc;": '\U00002AA6', "ltcir;": '\U00002A79', "ltdot;": '\U000022D6', "lthree;": '\U000022CB', "ltimes;": '\U000022C9', "ltlarr;": '\U00002976', "ltquest;": '\U00002A7B', "ltrPar;": '\U00002996', "ltri;": '\U000025C3', "ltrie;": '\U000022B4', "ltrif;": '\U000025C2', "lurdshar;": '\U0000294A', "luruhar;": '\U00002966', "mDDot;": '\U0000223A', "macr;": '\U000000AF', "male;": '\U00002642', "malt;": '\U00002720', "maltese;": '\U00002720', "map;": '\U000021A6', "mapsto;": '\U000021A6', "mapstodown;": '\U000021A7', "mapstoleft;": '\U000021A4', "mapstoup;": '\U000021A5', "marker;": '\U000025AE', "mcomma;": '\U00002A29', "mcy;": '\U0000043C', "mdash;": '\U00002014', "measuredangle;": '\U00002221', "mfr;": '\U0001D52A', "mho;": '\U00002127', "micro;": '\U000000B5', "mid;": '\U00002223', "midast;": '\U0000002A', "midcir;": '\U00002AF0', "middot;": '\U000000B7', "minus;": '\U00002212', "minusb;": '\U0000229F', "minusd;": '\U00002238', "minusdu;": '\U00002A2A', "mlcp;": '\U00002ADB', "mldr;": '\U00002026', "mnplus;": '\U00002213', "models;": '\U000022A7', "mopf;": '\U0001D55E', "mp;": '\U00002213', "mscr;": '\U0001D4C2', "mstpos;": '\U0000223E', "mu;": '\U000003BC', "multimap;": '\U000022B8', "mumap;": '\U000022B8', "nLeftarrow;": '\U000021CD', "nLeftrightarrow;": '\U000021CE', "nRightarrow;": '\U000021CF', "nVDash;": '\U000022AF', "nVdash;": '\U000022AE', "nabla;": '\U00002207', "nacute;": '\U00000144', "nap;": '\U00002249', "napos;": '\U00000149', "napprox;": '\U00002249', "natur;": '\U0000266E', "natural;": '\U0000266E', "naturals;": '\U00002115', "nbsp;": '\U000000A0', "ncap;": '\U00002A43', "ncaron;": '\U00000148', "ncedil;": '\U00000146', "ncong;": '\U00002247', "ncup;": '\U00002A42', "ncy;": '\U0000043D', "ndash;": '\U00002013', "ne;": '\U00002260', "neArr;": '\U000021D7', "nearhk;": '\U00002924', "nearr;": '\U00002197', "nearrow;": '\U00002197', "nequiv;": '\U00002262', "nesear;": '\U00002928', "nexist;": '\U00002204', "nexists;": '\U00002204', "nfr;": '\U0001D52B', "nge;": '\U00002271', "ngeq;": '\U00002271', "ngsim;": '\U00002275', "ngt;": '\U0000226F', "ngtr;": '\U0000226F', "nhArr;": '\U000021CE', "nharr;": '\U000021AE', "nhpar;": '\U00002AF2', "ni;": '\U0000220B', "nis;": '\U000022FC', "nisd;": '\U000022FA', "niv;": '\U0000220B', "njcy;": '\U0000045A', "nlArr;": '\U000021CD', "nlarr;": '\U0000219A', "nldr;": '\U00002025', "nle;": '\U00002270', "nleftarrow;": '\U0000219A', "nleftrightarrow;": '\U000021AE', "nleq;": '\U00002270', "nless;": '\U0000226E', "nlsim;": '\U00002274', "nlt;": '\U0000226E', "nltri;": '\U000022EA', "nltrie;": '\U000022EC', "nmid;": '\U00002224', "nopf;": '\U0001D55F', "not;": '\U000000AC', "notin;": '\U00002209', "notinva;": '\U00002209', "notinvb;": '\U000022F7', "notinvc;": '\U000022F6', "notni;": '\U0000220C', "notniva;": '\U0000220C', "notnivb;": '\U000022FE', "notnivc;": '\U000022FD', "npar;": '\U00002226', "nparallel;": '\U00002226', "npolint;": '\U00002A14', "npr;": '\U00002280', "nprcue;": '\U000022E0', "nprec;": '\U00002280', "nrArr;": '\U000021CF', "nrarr;": '\U0000219B', "nrightarrow;": '\U0000219B', "nrtri;": '\U000022EB', "nrtrie;": '\U000022ED', "nsc;": '\U00002281', "nsccue;": '\U000022E1', "nscr;": '\U0001D4C3', "nshortmid;": '\U00002224', "nshortparallel;": '\U00002226', "nsim;": '\U00002241', "nsime;": '\U00002244', "nsimeq;": '\U00002244', "nsmid;": '\U00002224', "nspar;": '\U00002226', "nsqsube;": '\U000022E2', "nsqsupe;": '\U000022E3', "nsub;": '\U00002284', "nsube;": '\U00002288', "nsubseteq;": '\U00002288', "nsucc;": '\U00002281', "nsup;": '\U00002285', "nsupe;": '\U00002289', "nsupseteq;": '\U00002289', "ntgl;": '\U00002279', "ntilde;": '\U000000F1', "ntlg;": '\U00002278', "ntriangleleft;": '\U000022EA', "ntrianglelefteq;": '\U000022EC', "ntriangleright;": '\U000022EB', "ntrianglerighteq;": '\U000022ED', "nu;": '\U000003BD', "num;": '\U00000023', "numero;": '\U00002116', "numsp;": '\U00002007', "nvDash;": '\U000022AD', "nvHarr;": '\U00002904', "nvdash;": '\U000022AC', "nvinfin;": '\U000029DE', "nvlArr;": '\U00002902', "nvrArr;": '\U00002903', "nwArr;": '\U000021D6', "nwarhk;": '\U00002923', "nwarr;": '\U00002196', "nwarrow;": '\U00002196', "nwnear;": '\U00002927', "oS;": '\U000024C8', "oacute;": '\U000000F3', "oast;": '\U0000229B', "ocir;": '\U0000229A', "ocirc;": '\U000000F4', "ocy;": '\U0000043E', "odash;": '\U0000229D', "odblac;": '\U00000151', "odiv;": '\U00002A38', "odot;": '\U00002299', "odsold;": '\U000029BC', "oelig;": '\U00000153', "ofcir;": '\U000029BF', "ofr;": '\U0001D52C', "ogon;": '\U000002DB', "ograve;": '\U000000F2', "ogt;": '\U000029C1', "ohbar;": '\U000029B5', "ohm;": '\U000003A9', "oint;": '\U0000222E', "olarr;": '\U000021BA', "olcir;": '\U000029BE', "olcross;": '\U000029BB', "oline;": '\U0000203E', "olt;": '\U000029C0', "omacr;": '\U0000014D', "omega;": '\U000003C9', "omicron;": '\U000003BF', "omid;": '\U000029B6', "ominus;": '\U00002296', "oopf;": '\U0001D560', "opar;": '\U000029B7', "operp;": '\U000029B9', "oplus;": '\U00002295', "or;": '\U00002228', "orarr;": '\U000021BB', "ord;": '\U00002A5D', "order;": '\U00002134', "orderof;": '\U00002134', "ordf;": '\U000000AA', "ordm;": '\U000000BA', "origof;": '\U000022B6', "oror;": '\U00002A56', "orslope;": '\U00002A57', "orv;": '\U00002A5B', "oscr;": '\U00002134', "oslash;": '\U000000F8', "osol;": '\U00002298', "otilde;": '\U000000F5', "otimes;": '\U00002297', "otimesas;": '\U00002A36', "ouml;": '\U000000F6', "ovbar;": '\U0000233D', "par;": '\U00002225', "para;": '\U000000B6', "parallel;": '\U00002225', "parsim;": '\U00002AF3', "parsl;": '\U00002AFD', "part;": '\U00002202', "pcy;": '\U0000043F', "percnt;": '\U00000025', "period;": '\U0000002E', "permil;": '\U00002030', "perp;": '\U000022A5', "pertenk;": '\U00002031', "pfr;": '\U0001D52D', "phi;": '\U000003C6', "phiv;": '\U000003D5', "phmmat;": '\U00002133', "phone;": '\U0000260E', "pi;": '\U000003C0', "pitchfork;": '\U000022D4', "piv;": '\U000003D6', "planck;": '\U0000210F', "planckh;": '\U0000210E', "plankv;": '\U0000210F', "plus;": '\U0000002B', "plusacir;": '\U00002A23', "plusb;": '\U0000229E', "pluscir;": '\U00002A22', "plusdo;": '\U00002214', "plusdu;": '\U00002A25', "pluse;": '\U00002A72', "plusmn;": '\U000000B1', "plussim;": '\U00002A26', "plustwo;": '\U00002A27', "pm;": '\U000000B1', "pointint;": '\U00002A15', "popf;": '\U0001D561', "pound;": '\U000000A3', "pr;": '\U0000227A', "prE;": '\U00002AB3', "prap;": '\U00002AB7', "prcue;": '\U0000227C', "pre;": '\U00002AAF', "prec;": '\U0000227A', "precapprox;": '\U00002AB7', "preccurlyeq;": '\U0000227C', "preceq;": '\U00002AAF', "precnapprox;": '\U00002AB9', "precneqq;": '\U00002AB5', "precnsim;": '\U000022E8', "precsim;": '\U0000227E', "prime;": '\U00002032', "primes;": '\U00002119', "prnE;": '\U00002AB5', "prnap;": '\U00002AB9', "prnsim;": '\U000022E8', "prod;": '\U0000220F', "profalar;": '\U0000232E', "profline;": '\U00002312', "profsurf;": '\U00002313', "prop;": '\U0000221D', "propto;": '\U0000221D', "prsim;": '\U0000227E', "prurel;": '\U000022B0', "pscr;": '\U0001D4C5', "psi;": '\U000003C8', "puncsp;": '\U00002008', "qfr;": '\U0001D52E', "qint;": '\U00002A0C', "qopf;": '\U0001D562', "qprime;": '\U00002057', "qscr;": '\U0001D4C6', "quaternions;": '\U0000210D', "quatint;": '\U00002A16', "quest;": '\U0000003F', "questeq;": '\U0000225F', "quot;": '\U00000022', "rAarr;": '\U000021DB', "rArr;": '\U000021D2', "rAtail;": '\U0000291C', "rBarr;": '\U0000290F', "rHar;": '\U00002964', "racute;": '\U00000155', "radic;": '\U0000221A', "raemptyv;": '\U000029B3', "rang;": '\U000027E9', "rangd;": '\U00002992', "range;": '\U000029A5', "rangle;": '\U000027E9', "raquo;": '\U000000BB', "rarr;": '\U00002192', "rarrap;": '\U00002975', "rarrb;": '\U000021E5', "rarrbfs;": '\U00002920', "rarrc;": '\U00002933', "rarrfs;": '\U0000291E', "rarrhk;": '\U000021AA', "rarrlp;": '\U000021AC', "rarrpl;": '\U00002945', "rarrsim;": '\U00002974', "rarrtl;": '\U000021A3', "rarrw;": '\U0000219D', "ratail;": '\U0000291A', "ratio;": '\U00002236', "rationals;": '\U0000211A', "rbarr;": '\U0000290D', "rbbrk;": '\U00002773', "rbrace;": '\U0000007D', "rbrack;": '\U0000005D', "rbrke;": '\U0000298C', "rbrksld;": '\U0000298E', "rbrkslu;": '\U00002990', "rcaron;": '\U00000159', "rcedil;": '\U00000157', "rceil;": '\U00002309', "rcub;": '\U0000007D', "rcy;": '\U00000440', "rdca;": '\U00002937', "rdldhar;": '\U00002969', "rdquo;": '\U0000201D', "rdquor;": '\U0000201D', "rdsh;": '\U000021B3', "real;": '\U0000211C', "realine;": '\U0000211B', "realpart;": '\U0000211C', "reals;": '\U0000211D', "rect;": '\U000025AD', "reg;": '\U000000AE', "rfisht;": '\U0000297D', "rfloor;": '\U0000230B', "rfr;": '\U0001D52F', "rhard;": '\U000021C1', "rharu;": '\U000021C0', "rharul;": '\U0000296C', "rho;": '\U000003C1', "rhov;": '\U000003F1', "rightarrow;": '\U00002192', "rightarrowtail;": '\U000021A3', "rightharpoondown;": '\U000021C1', "rightharpoonup;": '\U000021C0', "rightleftarrows;": '\U000021C4', "rightleftharpoons;": '\U000021CC', "rightrightarrows;": '\U000021C9', "rightsquigarrow;": '\U0000219D', "rightthreetimes;": '\U000022CC', "ring;": '\U000002DA', "risingdotseq;": '\U00002253', "rlarr;": '\U000021C4', "rlhar;": '\U000021CC', "rlm;": '\U0000200F', "rmoust;": '\U000023B1', "rmoustache;": '\U000023B1', "rnmid;": '\U00002AEE', "roang;": '\U000027ED', "roarr;": '\U000021FE', "robrk;": '\U000027E7', "ropar;": '\U00002986', "ropf;": '\U0001D563', "roplus;": '\U00002A2E', "rotimes;": '\U00002A35', "rpar;": '\U00000029', "rpargt;": '\U00002994', "rppolint;": '\U00002A12', "rrarr;": '\U000021C9', "rsaquo;": '\U0000203A', "rscr;": '\U0001D4C7', "rsh;": '\U000021B1', "rsqb;": '\U0000005D', "rsquo;": '\U00002019', "rsquor;": '\U00002019', "rthree;": '\U000022CC', "rtimes;": '\U000022CA', "rtri;": '\U000025B9', "rtrie;": '\U000022B5', "rtrif;": '\U000025B8', "rtriltri;": '\U000029CE', "ruluhar;": '\U00002968', "rx;": '\U0000211E', "sacute;": '\U0000015B', "sbquo;": '\U0000201A', "sc;": '\U0000227B', "scE;": '\U00002AB4', "scap;": '\U00002AB8', "scaron;": '\U00000161', "sccue;": '\U0000227D', "sce;": '\U00002AB0', "scedil;": '\U0000015F', "scirc;": '\U0000015D', "scnE;": '\U00002AB6', "scnap;": '\U00002ABA', "scnsim;": '\U000022E9', "scpolint;": '\U00002A13', "scsim;": '\U0000227F', "scy;": '\U00000441', "sdot;": '\U000022C5', "sdotb;": '\U000022A1', "sdote;": '\U00002A66', "seArr;": '\U000021D8', "searhk;": '\U00002925', "searr;": '\U00002198', "searrow;": '\U00002198', "sect;": '\U000000A7', "semi;": '\U0000003B', "seswar;": '\U00002929', "setminus;": '\U00002216', "setmn;": '\U00002216', "sext;": '\U00002736', "sfr;": '\U0001D530', "sfrown;": '\U00002322', "sharp;": '\U0000266F', "shchcy;": '\U00000449', "shcy;": '\U00000448', "shortmid;": '\U00002223', "shortparallel;": '\U00002225', "shy;": '\U000000AD', "sigma;": '\U000003C3', "sigmaf;": '\U000003C2', "sigmav;": '\U000003C2', "sim;": '\U0000223C', "simdot;": '\U00002A6A', "sime;": '\U00002243', "simeq;": '\U00002243', "simg;": '\U00002A9E', "simgE;": '\U00002AA0', "siml;": '\U00002A9D', "simlE;": '\U00002A9F', "simne;": '\U00002246', "simplus;": '\U00002A24', "simrarr;": '\U00002972', "slarr;": '\U00002190', "smallsetminus;": '\U00002216', "smashp;": '\U00002A33', "smeparsl;": '\U000029E4', "smid;": '\U00002223', "smile;": '\U00002323', "smt;": '\U00002AAA', "smte;": '\U00002AAC', "softcy;": '\U0000044C', "sol;": '\U0000002F', "solb;": '\U000029C4', "solbar;": '\U0000233F', "sopf;": '\U0001D564', "spades;": '\U00002660', "spadesuit;": '\U00002660', "spar;": '\U00002225', "sqcap;": '\U00002293', "sqcup;": '\U00002294', "sqsub;": '\U0000228F', "sqsube;": '\U00002291', "sqsubset;": '\U0000228F', "sqsubseteq;": '\U00002291', "sqsup;": '\U00002290', "sqsupe;": '\U00002292', "sqsupset;": '\U00002290', "sqsupseteq;": '\U00002292', "squ;": '\U000025A1', "square;": '\U000025A1', "squarf;": '\U000025AA', "squf;": '\U000025AA', "srarr;": '\U00002192', "sscr;": '\U0001D4C8', "ssetmn;": '\U00002216', "ssmile;": '\U00002323', "sstarf;": '\U000022C6', "star;": '\U00002606', "starf;": '\U00002605', "straightepsilon;": '\U000003F5', "straightphi;": '\U000003D5', "strns;": '\U000000AF', "sub;": '\U00002282', "subE;": '\U00002AC5', "subdot;": '\U00002ABD', "sube;": '\U00002286', "subedot;": '\U00002AC3', "submult;": '\U00002AC1', "subnE;": '\U00002ACB', "subne;": '\U0000228A', "subplus;": '\U00002ABF', "subrarr;": '\U00002979', "subset;": '\U00002282', "subseteq;": '\U00002286', "subseteqq;": '\U00002AC5', "subsetneq;": '\U0000228A', "subsetneqq;": '\U00002ACB', "subsim;": '\U00002AC7', "subsub;": '\U00002AD5', "subsup;": '\U00002AD3', "succ;": '\U0000227B', "succapprox;": '\U00002AB8', "succcurlyeq;": '\U0000227D', "succeq;": '\U00002AB0', "succnapprox;": '\U00002ABA', "succneqq;": '\U00002AB6', "succnsim;": '\U000022E9', "succsim;": '\U0000227F', "sum;": '\U00002211', "sung;": '\U0000266A', "sup;": '\U00002283', "sup1;": '\U000000B9', "sup2;": '\U000000B2', "sup3;": '\U000000B3', "supE;": '\U00002AC6', "supdot;": '\U00002ABE', "supdsub;": '\U00002AD8', "supe;": '\U00002287', "supedot;": '\U00002AC4', "suphsol;": '\U000027C9', "suphsub;": '\U00002AD7', "suplarr;": '\U0000297B', "supmult;": '\U00002AC2', "supnE;": '\U00002ACC', "supne;": '\U0000228B', "supplus;": '\U00002AC0', "supset;": '\U00002283', "supseteq;": '\U00002287', "supseteqq;": '\U00002AC6', "supsetneq;": '\U0000228B', "supsetneqq;": '\U00002ACC', "supsim;": '\U00002AC8', "supsub;": '\U00002AD4', "supsup;": '\U00002AD6', "swArr;": '\U000021D9', "swarhk;": '\U00002926', "swarr;": '\U00002199', "swarrow;": '\U00002199', "swnwar;": '\U0000292A', "szlig;": '\U000000DF', "target;": '\U00002316', "tau;": '\U000003C4', "tbrk;": '\U000023B4', "tcaron;": '\U00000165', "tcedil;": '\U00000163', "tcy;": '\U00000442', "tdot;": '\U000020DB', "telrec;": '\U00002315', "tfr;": '\U0001D531', "there4;": '\U00002234', "therefore;": '\U00002234', "theta;": '\U000003B8', "thetasym;": '\U000003D1', "thetav;": '\U000003D1', "thickapprox;": '\U00002248', "thicksim;": '\U0000223C', "thinsp;": '\U00002009', "thkap;": '\U00002248', "thksim;": '\U0000223C', "thorn;": '\U000000FE', "tilde;": '\U000002DC', "times;": '\U000000D7', "timesb;": '\U000022A0', "timesbar;": '\U00002A31', "timesd;": '\U00002A30', "tint;": '\U0000222D', "toea;": '\U00002928', "top;": '\U000022A4', "topbot;": '\U00002336', "topcir;": '\U00002AF1', "topf;": '\U0001D565', "topfork;": '\U00002ADA', "tosa;": '\U00002929', "tprime;": '\U00002034', "trade;": '\U00002122', "triangle;": '\U000025B5', "triangledown;": '\U000025BF', "triangleleft;": '\U000025C3', "trianglelefteq;": '\U000022B4', "triangleq;": '\U0000225C', "triangleright;": '\U000025B9', "trianglerighteq;": '\U000022B5', "tridot;": '\U000025EC', "trie;": '\U0000225C', "triminus;": '\U00002A3A', "triplus;": '\U00002A39', "trisb;": '\U000029CD', "tritime;": '\U00002A3B', "trpezium;": '\U000023E2', "tscr;": '\U0001D4C9', "tscy;": '\U00000446', "tshcy;": '\U0000045B', "tstrok;": '\U00000167', "twixt;": '\U0000226C', "twoheadleftarrow;": '\U0000219E', "twoheadrightarrow;": '\U000021A0', "uArr;": '\U000021D1', "uHar;": '\U00002963', "uacute;": '\U000000FA', "uarr;": '\U00002191', "ubrcy;": '\U0000045E', "ubreve;": '\U0000016D', "ucirc;": '\U000000FB', "ucy;": '\U00000443', "udarr;": '\U000021C5', "udblac;": '\U00000171', "udhar;": '\U0000296E', "ufisht;": '\U0000297E', "ufr;": '\U0001D532', "ugrave;": '\U000000F9', "uharl;": '\U000021BF', "uharr;": '\U000021BE', "uhblk;": '\U00002580', "ulcorn;": '\U0000231C', "ulcorner;": '\U0000231C', "ulcrop;": '\U0000230F', "ultri;": '\U000025F8', "umacr;": '\U0000016B', "uml;": '\U000000A8', "uogon;": '\U00000173', "uopf;": '\U0001D566', "uparrow;": '\U00002191', "updownarrow;": '\U00002195', "upharpoonleft;": '\U000021BF', "upharpoonright;": '\U000021BE', "uplus;": '\U0000228E', "upsi;": '\U000003C5', "upsih;": '\U000003D2', "upsilon;": '\U000003C5', "upuparrows;": '\U000021C8', "urcorn;": '\U0000231D', "urcorner;": '\U0000231D', "urcrop;": '\U0000230E', "uring;": '\U0000016F', "urtri;": '\U000025F9', "uscr;": '\U0001D4CA', "utdot;": '\U000022F0', "utilde;": '\U00000169', "utri;": '\U000025B5', "utrif;": '\U000025B4', "uuarr;": '\U000021C8', "uuml;": '\U000000FC', "uwangle;": '\U000029A7', "vArr;": '\U000021D5', "vBar;": '\U00002AE8', "vBarv;": '\U00002AE9', "vDash;": '\U000022A8', "vangrt;": '\U0000299C', "varepsilon;": '\U000003F5', "varkappa;": '\U000003F0', "varnothing;": '\U00002205', "varphi;": '\U000003D5', "varpi;": '\U000003D6', "varpropto;": '\U0000221D', "varr;": '\U00002195', "varrho;": '\U000003F1', "varsigma;": '\U000003C2', "vartheta;": '\U000003D1', "vartriangleleft;": '\U000022B2', "vartriangleright;": '\U000022B3', "vcy;": '\U00000432', "vdash;": '\U000022A2', "vee;": '\U00002228', "veebar;": '\U000022BB', "veeeq;": '\U0000225A', "vellip;": '\U000022EE', "verbar;": '\U0000007C', "vert;": '\U0000007C', "vfr;": '\U0001D533', "vltri;": '\U000022B2', "vopf;": '\U0001D567', "vprop;": '\U0000221D', "vrtri;": '\U000022B3', "vscr;": '\U0001D4CB', "vzigzag;": '\U0000299A', "wcirc;": '\U00000175', "wedbar;": '\U00002A5F', "wedge;": '\U00002227', "wedgeq;": '\U00002259', "weierp;": '\U00002118', "wfr;": '\U0001D534', "wopf;": '\U0001D568', "wp;": '\U00002118', "wr;": '\U00002240', "wreath;": '\U00002240', "wscr;": '\U0001D4CC', "xcap;": '\U000022C2', "xcirc;": '\U000025EF', "xcup;": '\U000022C3', "xdtri;": '\U000025BD', "xfr;": '\U0001D535', "xhArr;": '\U000027FA', "xharr;": '\U000027F7', "xi;": '\U000003BE', "xlArr;": '\U000027F8', "xlarr;": '\U000027F5', "xmap;": '\U000027FC', "xnis;": '\U000022FB', "xodot;": '\U00002A00', "xopf;": '\U0001D569', "xoplus;": '\U00002A01', "xotime;": '\U00002A02', "xrArr;": '\U000027F9', "xrarr;": '\U000027F6', "xscr;": '\U0001D4CD', "xsqcup;": '\U00002A06', "xuplus;": '\U00002A04', "xutri;": '\U000025B3', "xvee;": '\U000022C1', "xwedge;": '\U000022C0', "yacute;": '\U000000FD', "yacy;": '\U0000044F', "ycirc;": '\U00000177', "ycy;": '\U0000044B', "yen;": '\U000000A5', "yfr;": '\U0001D536', "yicy;": '\U00000457', "yopf;": '\U0001D56A', "yscr;": '\U0001D4CE', "yucy;": '\U0000044E', "yuml;": '\U000000FF', "zacute;": '\U0000017A', "zcaron;": '\U0000017E', "zcy;": '\U00000437', "zdot;": '\U0000017C', "zeetrf;": '\U00002128', "zeta;": '\U000003B6', "zfr;": '\U0001D537', "zhcy;": '\U00000436', "zigrarr;": '\U000021DD', "zopf;": '\U0001D56B', "zscr;": '\U0001D4CF', "zwj;": '\U0000200D', "zwnj;": '\U0000200C', "AElig": '\U000000C6', "AMP": '\U00000026', "Aacute": '\U000000C1', "Acirc": '\U000000C2', "Agrave": '\U000000C0', "Aring": '\U000000C5', "Atilde": '\U000000C3', "Auml": '\U000000C4', "COPY": '\U000000A9', "Ccedil": '\U000000C7', "ETH": '\U000000D0', "Eacute": '\U000000C9', "Ecirc": '\U000000CA', "Egrave": '\U000000C8', "Euml": '\U000000CB', "GT": '\U0000003E', "Iacute": '\U000000CD', "Icirc": '\U000000CE', "Igrave": '\U000000CC', "Iuml": '\U000000CF', "LT": '\U0000003C', "Ntilde": '\U000000D1', "Oacute": '\U000000D3', "Ocirc": '\U000000D4', "Ograve": '\U000000D2', "Oslash": '\U000000D8', "Otilde": '\U000000D5', "Ouml": '\U000000D6', "QUOT": '\U00000022', "REG": '\U000000AE', "THORN": '\U000000DE', "Uacute": '\U000000DA', "Ucirc": '\U000000DB', "Ugrave": '\U000000D9', "Uuml": '\U000000DC', "Yacute": '\U000000DD', "aacute": '\U000000E1', "acirc": '\U000000E2', "acute": '\U000000B4', "aelig": '\U000000E6', "agrave": '\U000000E0', "amp": '\U00000026', "aring": '\U000000E5', "atilde": '\U000000E3', "auml": '\U000000E4', "brvbar": '\U000000A6', "ccedil": '\U000000E7', "cedil": '\U000000B8', "cent": '\U000000A2', "copy": '\U000000A9', "curren": '\U000000A4', "deg": '\U000000B0', "divide": '\U000000F7', "eacute": '\U000000E9', "ecirc": '\U000000EA', "egrave": '\U000000E8', "eth": '\U000000F0', "euml": '\U000000EB', "frac12": '\U000000BD', "frac14": '\U000000BC', "frac34": '\U000000BE', "gt": '\U0000003E', "iacute": '\U000000ED', "icirc": '\U000000EE', "iexcl": '\U000000A1', "igrave": '\U000000EC', "iquest": '\U000000BF', "iuml": '\U000000EF', "laquo": '\U000000AB', "lt": '\U0000003C', "macr": '\U000000AF', "micro": '\U000000B5', "middot": '\U000000B7', "nbsp": '\U000000A0', "not": '\U000000AC', "ntilde": '\U000000F1', "oacute": '\U000000F3', "ocirc": '\U000000F4', "ograve": '\U000000F2', "ordf": '\U000000AA', "ordm": '\U000000BA', "oslash": '\U000000F8', "otilde": '\U000000F5', "ouml": '\U000000F6', "para": '\U000000B6', "plusmn": '\U000000B1', "pound": '\U000000A3', "quot": '\U00000022', "raquo": '\U000000BB', "reg": '\U000000AE', "sect": '\U000000A7', "shy": '\U000000AD', "sup1": '\U000000B9', "sup2": '\U000000B2', "sup3": '\U000000B3', "szlig": '\U000000DF', "thorn": '\U000000FE', "times": '\U000000D7', "uacute": '\U000000FA', "ucirc": '\U000000FB', "ugrave": '\U000000F9', "uml": '\U000000A8', "uuml": '\U000000FC', "yacute": '\U000000FD', "yen": '\U000000A5', "yuml": '\U000000FF', } // HTML entities that are two unicode codepoints. var entity2 = map[string][2]rune{ // TODO(nigeltao): Handle replacements that are wider than their names. // "nLt;": {'\u226A', '\u20D2'}, // "nGt;": {'\u226B', '\u20D2'}, "NotEqualTilde;": {'\u2242', '\u0338'}, "NotGreaterFullEqual;": {'\u2267', '\u0338'}, "NotGreaterGreater;": {'\u226B', '\u0338'}, "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'}, "NotHumpDownHump;": {'\u224E', '\u0338'}, "NotHumpEqual;": {'\u224F', '\u0338'}, "NotLeftTriangleBar;": {'\u29CF', '\u0338'}, "NotLessLess;": {'\u226A', '\u0338'}, "NotLessSlantEqual;": {'\u2A7D', '\u0338'}, "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'}, "NotNestedLessLess;": {'\u2AA1', '\u0338'}, "NotPrecedesEqual;": {'\u2AAF', '\u0338'}, "NotRightTriangleBar;": {'\u29D0', '\u0338'}, "NotSquareSubset;": {'\u228F', '\u0338'}, "NotSquareSuperset;": {'\u2290', '\u0338'}, "NotSubset;": {'\u2282', '\u20D2'}, "NotSucceedsEqual;": {'\u2AB0', '\u0338'}, "NotSucceedsTilde;": {'\u227F', '\u0338'}, "NotSuperset;": {'\u2283', '\u20D2'}, "ThickSpace;": {'\u205F', '\u200A'}, "acE;": {'\u223E', '\u0333'}, "bne;": {'\u003D', '\u20E5'}, "bnequiv;": {'\u2261', '\u20E5'}, "caps;": {'\u2229', '\uFE00'}, "cups;": {'\u222A', '\uFE00'}, "fjlig;": {'\u0066', '\u006A'}, "gesl;": {'\u22DB', '\uFE00'}, "gvertneqq;": {'\u2269', '\uFE00'}, "gvnE;": {'\u2269', '\uFE00'}, "lates;": {'\u2AAD', '\uFE00'}, "lesg;": {'\u22DA', '\uFE00'}, "lvertneqq;": {'\u2268', '\uFE00'}, "lvnE;": {'\u2268', '\uFE00'}, "nGg;": {'\u22D9', '\u0338'}, "nGtv;": {'\u226B', '\u0338'}, "nLl;": {'\u22D8', '\u0338'}, "nLtv;": {'\u226A', '\u0338'}, "nang;": {'\u2220', '\u20D2'}, "napE;": {'\u2A70', '\u0338'}, "napid;": {'\u224B', '\u0338'}, "nbump;": {'\u224E', '\u0338'}, "nbumpe;": {'\u224F', '\u0338'}, "ncongdot;": {'\u2A6D', '\u0338'}, "nedot;": {'\u2250', '\u0338'}, "nesim;": {'\u2242', '\u0338'}, "ngE;": {'\u2267', '\u0338'}, "ngeqq;": {'\u2267', '\u0338'}, "ngeqslant;": {'\u2A7E', '\u0338'}, "nges;": {'\u2A7E', '\u0338'}, "nlE;": {'\u2266', '\u0338'}, "nleqq;": {'\u2266', '\u0338'}, "nleqslant;": {'\u2A7D', '\u0338'}, "nles;": {'\u2A7D', '\u0338'}, "notinE;": {'\u22F9', '\u0338'}, "notindot;": {'\u22F5', '\u0338'}, "nparsl;": {'\u2AFD', '\u20E5'}, "npart;": {'\u2202', '\u0338'}, "npre;": {'\u2AAF', '\u0338'}, "npreceq;": {'\u2AAF', '\u0338'}, "nrarrc;": {'\u2933', '\u0338'}, "nrarrw;": {'\u219D', '\u0338'}, "nsce;": {'\u2AB0', '\u0338'}, "nsubE;": {'\u2AC5', '\u0338'}, "nsubset;": {'\u2282', '\u20D2'}, "nsubseteqq;": {'\u2AC5', '\u0338'}, "nsucceq;": {'\u2AB0', '\u0338'}, "nsupE;": {'\u2AC6', '\u0338'}, "nsupset;": {'\u2283', '\u20D2'}, "nsupseteqq;": {'\u2AC6', '\u0338'}, "nvap;": {'\u224D', '\u20D2'}, "nvge;": {'\u2265', '\u20D2'}, "nvgt;": {'\u003E', '\u20D2'}, "nvle;": {'\u2264', '\u20D2'}, "nvlt;": {'\u003C', '\u20D2'}, "nvltrie;": {'\u22B4', '\u20D2'}, "nvrtrie;": {'\u22B5', '\u20D2'}, "nvsim;": {'\u223C', '\u20D2'}, "race;": {'\u223D', '\u0331'}, "smtes;": {'\u2AAC', '\uFE00'}, "sqcaps;": {'\u2293', '\uFE00'}, "sqcups;": {'\u2294', '\uFE00'}, "varsubsetneq;": {'\u228A', '\uFE00'}, "varsubsetneqq;": {'\u2ACB', '\uFE00'}, "varsupsetneq;": {'\u228B', '\uFE00'}, "varsupsetneqq;": {'\u2ACC', '\uFE00'}, "vnsub;": {'\u2282', '\u20D2'}, "vnsup;": {'\u2283', '\u20D2'}, "vsubnE;": {'\u2ACB', '\uFE00'}, "vsubne;": {'\u228A', '\uFE00'}, "vsupnE;": {'\u2ACC', '\uFE00'}, "vsupne;": {'\u228B', '\uFE00'}, } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/entity_test.go000066400000000000000000000017761264464372400243210ustar00rootroot00000000000000// 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 html import ( "testing" "unicode/utf8" ) func TestEntityLength(t *testing.T) { // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key). // The +1 comes from the leading "&". This property implies that the length of // unescaped text is <= the length of escaped text. for k, v := range entity { if 1+len(k) < utf8.RuneLen(v) { t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v)) } if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' { t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon) } } for k, v := range entity2 { if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) { t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1])) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/escape.go000066400000000000000000000136451264464372400232040ustar00rootroot00000000000000// 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 html import ( "bytes" "strings" "unicode/utf8" ) // These replacements permit compatibility with old numeric entities that // assumed Windows-1252 encoding. // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference var replacementTable = [...]rune{ '\u20AC', // First entry is what 0x80 should be replaced with. '\u0081', '\u201A', '\u0192', '\u201E', '\u2026', '\u2020', '\u2021', '\u02C6', '\u2030', '\u0160', '\u2039', '\u0152', '\u008D', '\u017D', '\u008F', '\u0090', '\u2018', '\u2019', '\u201C', '\u201D', '\u2022', '\u2013', '\u2014', '\u02DC', '\u2122', '\u0161', '\u203A', '\u0153', '\u009D', '\u017E', '\u0178', // Last entry is 0x9F. // 0x00->'\uFFFD' is handled programmatically. // 0x0D->'\u000D' is a no-op. } // unescapeEntity reads an entity like "<" from b[src:] and writes the // corresponding "<" to b[dst:], returning the incremented dst and src cursors. // Precondition: b[src] == '&' && dst <= src. // attribute should be true if parsing an attribute value. func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference // i starts at 1 because we already know that s[0] == '&'. i, s := 1, b[src:] if len(s) <= 1 { b[dst] = b[src] return dst + 1, src + 1 } if s[i] == '#' { if len(s) <= 3 { // We need to have at least "&#.". b[dst] = b[src] return dst + 1, src + 1 } i++ c := s[i] hex := false if c == 'x' || c == 'X' { hex = true i++ } x := '\x00' for i < len(s) { c = s[i] i++ if hex { if '0' <= c && c <= '9' { x = 16*x + rune(c) - '0' continue } else if 'a' <= c && c <= 'f' { x = 16*x + rune(c) - 'a' + 10 continue } else if 'A' <= c && c <= 'F' { x = 16*x + rune(c) - 'A' + 10 continue } } else if '0' <= c && c <= '9' { x = 10*x + rune(c) - '0' continue } if c != ';' { i-- } break } if i <= 3 { // No characters matched. b[dst] = b[src] return dst + 1, src + 1 } if 0x80 <= x && x <= 0x9F { // Replace characters from Windows-1252 with UTF-8 equivalents. x = replacementTable[x-0x80] } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF { // Replace invalid characters with the replacement character. x = '\uFFFD' } return dst + utf8.EncodeRune(b[dst:], x), src + i } // Consume the maximum number of characters possible, with the // consumed characters matching one of the named references. for i < len(s) { c := s[i] i++ // Lower-cased characters are more common in entities, so we check for them first. if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { continue } if c != ';' { i-- } break } entityName := string(s[1:i]) if entityName == "" { // No-op. } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { // No-op. } else if x := entity[entityName]; x != 0 { return dst + utf8.EncodeRune(b[dst:], x), src + i } else if x := entity2[entityName]; x[0] != 0 { dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i } else if !attribute { maxLen := len(entityName) - 1 if maxLen > longestEntityWithoutSemicolon { maxLen = longestEntityWithoutSemicolon } for j := maxLen; j > 1; j-- { if x := entity[entityName[:j]]; x != 0 { return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 } } } dst1, src1 = dst+i, src+i copy(b[dst:dst1], b[src:src1]) return dst1, src1 } // unescape unescapes b's entities in-place, so that "a<b" becomes "a': esc = ">" case '"': // """ is shorter than """. esc = """ case '\r': esc = " " default: panic("unrecognized escape character") } s = s[i+1:] if _, err := w.WriteString(esc); err != nil { return err } i = strings.IndexAny(s, escapedChars) } _, err := w.WriteString(s) return err } // EscapeString escapes special characters like "<" to become "<". It // escapes only five such characters: <, >, &, ' and ". // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't // always true. func EscapeString(s string) string { if strings.IndexAny(s, escapedChars) == -1 { return s } var buf bytes.Buffer escape(&buf, s) return buf.String() } // UnescapeString unescapes entities like "<" to become "<". It unescapes a // larger range of entities than EscapeString escapes. For example, "á" // unescapes to "á", as does "á" and "&xE1;". // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't // always true. func UnescapeString(s string) string { for _, c := range s { if c == '&' { return string(unescape([]byte(s), false)) } } return s } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/escape_test.go000066400000000000000000000035351264464372400242400ustar00rootroot00000000000000// Copyright 2013 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 html import "testing" type unescapeTest struct { // A short description of the test case. desc string // The HTML text. html string // The unescaped text. unescaped string } var unescapeTests = []unescapeTest{ // Handle no entities. { "copy", "A\ttext\nstring", "A\ttext\nstring", }, // Handle simple named entities. { "simple", "& > <", "& > <", }, // Handle hitting the end of the string. { "stringEnd", "& &", "& &", }, // Handle entities with two codepoints. { "multiCodepoint", "text ⋛︀ blah", "text \u22db\ufe00 blah", }, // Handle decimal numeric entities. { "decimalEntity", "Delta = Δ ", "Delta = Δ ", }, // Handle hexadecimal numeric entities. { "hexadecimalEntity", "Lambda = λ = λ ", "Lambda = λ = λ ", }, // Handle numeric early termination. { "numericEnds", "&# &#x €43 © = ©f = ©", "&# &#x €43 © = ©f = ©", }, // Handle numeric ISO-8859-1 entity replacements. { "numericReplacements", "Footnote‡", "Footnote‡", }, } func TestUnescape(t *testing.T) { for _, tt := range unescapeTests { unescaped := UnescapeString(tt.html) if unescaped != tt.unescaped { t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped) } } } func TestUnescapeEscape(t *testing.T) { ss := []string{ ``, `abc def`, `a & b`, `a&b`, `a & b`, `"`, `"`, `"<&>"`, `"<&>"`, `3&5==1 && 0<1, "0<1", a+acute=á`, `The special characters are: <, >, &, ' and "`, } for _, s := range ss { if got := UnescapeString(EscapeString(s)); got != s { t.Errorf("got %q want %q", got, s) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/example_test.go000066400000000000000000000015021264464372400244230ustar00rootroot00000000000000// Copyright 2012 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. // This example demonstrates parsing HTML data and walking the resulting tree. package html_test import ( "fmt" "log" "strings" "golang.org/x/net/html" ) func ExampleParse() { s := `

Links:

` doc, err := html.Parse(strings.NewReader(s)) if err != nil { log.Fatal(err) } var f func(*html.Node) f = func(n *html.Node) { if n.Type == html.ElementNode && n.Data == "a" { for _, a := range n.Attr { if a.Key == "href" { fmt.Println(a.Val) break } } } for c := n.FirstChild; c != nil; c = c.NextSibling { f(c) } } f(doc) // Output: // foo // /bar/baz } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/foreign.go000066400000000000000000000154011264464372400233650ustar00rootroot00000000000000// 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 html import ( "strings" ) func adjustAttributeNames(aa []Attribute, nameMap map[string]string) { for i := range aa { if newName, ok := nameMap[aa[i].Key]; ok { aa[i].Key = newName } } } func adjustForeignAttributes(aa []Attribute) { for i, a := range aa { if a.Key == "" || a.Key[0] != 'x' { continue } switch a.Key { case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink": j := strings.Index(a.Key, ":") aa[i].Namespace = a.Key[:j] aa[i].Key = a.Key[j+1:] } } } func htmlIntegrationPoint(n *Node) bool { if n.Type != ElementNode { return false } switch n.Namespace { case "math": if n.Data == "annotation-xml" { for _, a := range n.Attr { if a.Key == "encoding" { val := strings.ToLower(a.Val) if val == "text/html" || val == "application/xhtml+xml" { return true } } } } case "svg": switch n.Data { case "desc", "foreignObject", "title": return true } } return false } func mathMLTextIntegrationPoint(n *Node) bool { if n.Namespace != "math" { return false } switch n.Data { case "mi", "mo", "mn", "ms", "mtext": return true } return false } // Section 12.2.5.5. var breakout = map[string]bool{ "b": true, "big": true, "blockquote": true, "body": true, "br": true, "center": true, "code": true, "dd": true, "div": true, "dl": true, "dt": true, "em": true, "embed": true, "h1": true, "h2": true, "h3": true, "h4": true, "h5": true, "h6": true, "head": true, "hr": true, "i": true, "img": true, "li": true, "listing": true, "menu": true, "meta": true, "nobr": true, "ol": true, "p": true, "pre": true, "ruby": true, "s": true, "small": true, "span": true, "strong": true, "strike": true, "sub": true, "sup": true, "table": true, "tt": true, "u": true, "ul": true, "var": true, } // Section 12.2.5.5. var svgTagNameAdjustments = map[string]string{ "altglyph": "altGlyph", "altglyphdef": "altGlyphDef", "altglyphitem": "altGlyphItem", "animatecolor": "animateColor", "animatemotion": "animateMotion", "animatetransform": "animateTransform", "clippath": "clipPath", "feblend": "feBlend", "fecolormatrix": "feColorMatrix", "fecomponenttransfer": "feComponentTransfer", "fecomposite": "feComposite", "feconvolvematrix": "feConvolveMatrix", "fediffuselighting": "feDiffuseLighting", "fedisplacementmap": "feDisplacementMap", "fedistantlight": "feDistantLight", "feflood": "feFlood", "fefunca": "feFuncA", "fefuncb": "feFuncB", "fefuncg": "feFuncG", "fefuncr": "feFuncR", "fegaussianblur": "feGaussianBlur", "feimage": "feImage", "femerge": "feMerge", "femergenode": "feMergeNode", "femorphology": "feMorphology", "feoffset": "feOffset", "fepointlight": "fePointLight", "fespecularlighting": "feSpecularLighting", "fespotlight": "feSpotLight", "fetile": "feTile", "feturbulence": "feTurbulence", "foreignobject": "foreignObject", "glyphref": "glyphRef", "lineargradient": "linearGradient", "radialgradient": "radialGradient", "textpath": "textPath", } // Section 12.2.5.1 var mathMLAttributeAdjustments = map[string]string{ "definitionurl": "definitionURL", } var svgAttributeAdjustments = map[string]string{ "attributename": "attributeName", "attributetype": "attributeType", "basefrequency": "baseFrequency", "baseprofile": "baseProfile", "calcmode": "calcMode", "clippathunits": "clipPathUnits", "contentscripttype": "contentScriptType", "contentstyletype": "contentStyleType", "diffuseconstant": "diffuseConstant", "edgemode": "edgeMode", "externalresourcesrequired": "externalResourcesRequired", "filterres": "filterRes", "filterunits": "filterUnits", "glyphref": "glyphRef", "gradienttransform": "gradientTransform", "gradientunits": "gradientUnits", "kernelmatrix": "kernelMatrix", "kernelunitlength": "kernelUnitLength", "keypoints": "keyPoints", "keysplines": "keySplines", "keytimes": "keyTimes", "lengthadjust": "lengthAdjust", "limitingconeangle": "limitingConeAngle", "markerheight": "markerHeight", "markerunits": "markerUnits", "markerwidth": "markerWidth", "maskcontentunits": "maskContentUnits", "maskunits": "maskUnits", "numoctaves": "numOctaves", "pathlength": "pathLength", "patterncontentunits": "patternContentUnits", "patterntransform": "patternTransform", "patternunits": "patternUnits", "pointsatx": "pointsAtX", "pointsaty": "pointsAtY", "pointsatz": "pointsAtZ", "preservealpha": "preserveAlpha", "preserveaspectratio": "preserveAspectRatio", "primitiveunits": "primitiveUnits", "refx": "refX", "refy": "refY", "repeatcount": "repeatCount", "repeatdur": "repeatDur", "requiredextensions": "requiredExtensions", "requiredfeatures": "requiredFeatures", "specularconstant": "specularConstant", "specularexponent": "specularExponent", "spreadmethod": "spreadMethod", "startoffset": "startOffset", "stddeviation": "stdDeviation", "stitchtiles": "stitchTiles", "surfacescale": "surfaceScale", "systemlanguage": "systemLanguage", "tablevalues": "tableValues", "targetx": "targetX", "targety": "targetY", "textlength": "textLength", "viewbox": "viewBox", "viewtarget": "viewTarget", "xchannelselector": "xChannelSelector", "ychannelselector": "yChannelSelector", "zoomandpan": "zoomAndPan", } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/node.go000066400000000000000000000113431264464372400226620ustar00rootroot00000000000000// 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 html import ( "golang.org/x/net/html/atom" ) // A NodeType is the type of a Node. type NodeType uint32 const ( ErrorNode NodeType = iota TextNode DocumentNode ElementNode CommentNode DoctypeNode scopeMarkerNode ) // Section 12.2.3.3 says "scope markers are inserted when entering applet // elements, buttons, object elements, marquees, table cells, and table // captions, and are used to prevent formatting from 'leaking'". var scopeMarker = Node{Type: scopeMarkerNode} // A Node consists of a NodeType and some Data (tag name for element nodes, // content for text) and are part of a tree of Nodes. Element nodes may also // have a Namespace and contain a slice of Attributes. Data is unescaped, so // that it looks like "a 0 { return (*s)[i-1] } return nil } // index returns the index of the top-most occurrence of n in the stack, or -1 // if n is not present. func (s *nodeStack) index(n *Node) int { for i := len(*s) - 1; i >= 0; i-- { if (*s)[i] == n { return i } } return -1 } // insert inserts a node at the given index. func (s *nodeStack) insert(i int, n *Node) { (*s) = append(*s, nil) copy((*s)[i+1:], (*s)[i:]) (*s)[i] = n } // remove removes a node from the stack. It is a no-op if n is not present. func (s *nodeStack) remove(n *Node) { i := s.index(n) if i == -1 { return } copy((*s)[i:], (*s)[i+1:]) j := len(*s) - 1 (*s)[j] = nil *s = (*s)[:j] } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/node_test.go000066400000000000000000000073051264464372400237240ustar00rootroot00000000000000// 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 html import ( "fmt" ) // checkTreeConsistency checks that a node and its descendants are all // consistent in their parent/child/sibling relationships. func checkTreeConsistency(n *Node) error { return checkTreeConsistency1(n, 0) } func checkTreeConsistency1(n *Node, depth int) error { if depth == 1e4 { return fmt.Errorf("html: tree looks like it contains a cycle") } if err := checkNodeConsistency(n); err != nil { return err } for c := n.FirstChild; c != nil; c = c.NextSibling { if err := checkTreeConsistency1(c, depth+1); err != nil { return err } } return nil } // checkNodeConsistency checks that a node's parent/child/sibling relationships // are consistent. func checkNodeConsistency(n *Node) error { if n == nil { return nil } nParent := 0 for p := n.Parent; p != nil; p = p.Parent { nParent++ if nParent == 1e4 { return fmt.Errorf("html: parent list looks like an infinite loop") } } nForward := 0 for c := n.FirstChild; c != nil; c = c.NextSibling { nForward++ if nForward == 1e6 { return fmt.Errorf("html: forward list of children looks like an infinite loop") } if c.Parent != n { return fmt.Errorf("html: inconsistent child/parent relationship") } } nBackward := 0 for c := n.LastChild; c != nil; c = c.PrevSibling { nBackward++ if nBackward == 1e6 { return fmt.Errorf("html: backward list of children looks like an infinite loop") } if c.Parent != n { return fmt.Errorf("html: inconsistent child/parent relationship") } } if n.Parent != nil { if n.Parent == n { return fmt.Errorf("html: inconsistent parent relationship") } if n.Parent == n.FirstChild { return fmt.Errorf("html: inconsistent parent/first relationship") } if n.Parent == n.LastChild { return fmt.Errorf("html: inconsistent parent/last relationship") } if n.Parent == n.PrevSibling { return fmt.Errorf("html: inconsistent parent/prev relationship") } if n.Parent == n.NextSibling { return fmt.Errorf("html: inconsistent parent/next relationship") } parentHasNAsAChild := false for c := n.Parent.FirstChild; c != nil; c = c.NextSibling { if c == n { parentHasNAsAChild = true break } } if !parentHasNAsAChild { return fmt.Errorf("html: inconsistent parent/child relationship") } } if n.PrevSibling != nil && n.PrevSibling.NextSibling != n { return fmt.Errorf("html: inconsistent prev/next relationship") } if n.NextSibling != nil && n.NextSibling.PrevSibling != n { return fmt.Errorf("html: inconsistent next/prev relationship") } if (n.FirstChild == nil) != (n.LastChild == nil) { return fmt.Errorf("html: inconsistent first/last relationship") } if n.FirstChild != nil && n.FirstChild == n.LastChild { // We have a sole child. if n.FirstChild.PrevSibling != nil || n.FirstChild.NextSibling != nil { return fmt.Errorf("html: inconsistent sole child's sibling relationship") } } seen := map[*Node]bool{} var last *Node for c := n.FirstChild; c != nil; c = c.NextSibling { if seen[c] { return fmt.Errorf("html: inconsistent repeated child") } seen[c] = true last = c } if last != n.LastChild { return fmt.Errorf("html: inconsistent last relationship") } var first *Node for c := n.LastChild; c != nil; c = c.PrevSibling { if !seen[c] { return fmt.Errorf("html: inconsistent missing child") } delete(seen, c) first = c } if first != n.FirstChild { return fmt.Errorf("html: inconsistent first relationship") } if len(seen) != 0 { return fmt.Errorf("html: inconsistent forwards/backwards child list") } return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/parse.go000066400000000000000000001401621264464372400230510ustar00rootroot00000000000000// 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 html import ( "errors" "fmt" "io" "strings" a "golang.org/x/net/html/atom" ) // A parser implements the HTML5 parsing algorithm: // https://html.spec.whatwg.org/multipage/syntax.html#tree-construction type parser struct { // tokenizer provides the tokens for the parser. tokenizer *Tokenizer // tok is the most recently read token. tok Token // Self-closing tags like
are treated as start tags, except that // hasSelfClosingToken is set while they are being processed. hasSelfClosingToken bool // doc is the document root element. doc *Node // The stack of open elements (section 12.2.3.2) and active formatting // elements (section 12.2.3.3). oe, afe nodeStack // Element pointers (section 12.2.3.4). head, form *Node // Other parsing state flags (section 12.2.3.5). scripting, framesetOK bool // im is the current insertion mode. im insertionMode // originalIM is the insertion mode to go back to after completing a text // or inTableText insertion mode. originalIM insertionMode // fosterParenting is whether new elements should be inserted according to // the foster parenting rules (section 12.2.5.3). fosterParenting bool // quirks is whether the parser is operating in "quirks mode." quirks bool // fragment is whether the parser is parsing an HTML fragment. fragment bool // context is the context element when parsing an HTML fragment // (section 12.4). context *Node } func (p *parser) top() *Node { if n := p.oe.top(); n != nil { return n } return p.doc } // Stop tags for use in popUntil. These come from section 12.2.3.2. var ( defaultScopeStopTags = map[string][]a.Atom{ "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext}, "svg": {a.Desc, a.ForeignObject, a.Title}, } ) type scope int const ( defaultScope scope = iota listItemScope buttonScope tableScope tableRowScope tableBodyScope selectScope ) // popUntil pops the stack of open elements at the highest element whose tag // is in matchTags, provided there is no higher element in the scope's stop // tags (as defined in section 12.2.3.2). It returns whether or not there was // such an element. If there was not, popUntil leaves the stack unchanged. // // For example, the set of stop tags for table scope is: "html", "table". If // the stack was: // ["html", "body", "font", "table", "b", "i", "u"] // then popUntil(tableScope, "font") would return false, but // popUntil(tableScope, "i") would return true and the stack would become: // ["html", "body", "font", "table", "b"] // // If an element's tag is in both the stop tags and matchTags, then the stack // will be popped and the function returns true (provided, of course, there was // no higher element in the stack that was also in the stop tags). For example, // popUntil(tableScope, "table") returns true and leaves: // ["html", "body", "font"] func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool { if i := p.indexOfElementInScope(s, matchTags...); i != -1 { p.oe = p.oe[:i] return true } return false } // indexOfElementInScope returns the index in p.oe of the highest element whose // tag is in matchTags that is in scope. If no matching element is in scope, it // returns -1. func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int { for i := len(p.oe) - 1; i >= 0; i-- { tagAtom := p.oe[i].DataAtom if p.oe[i].Namespace == "" { for _, t := range matchTags { if t == tagAtom { return i } } switch s { case defaultScope: // No-op. case listItemScope: if tagAtom == a.Ol || tagAtom == a.Ul { return -1 } case buttonScope: if tagAtom == a.Button { return -1 } case tableScope: if tagAtom == a.Html || tagAtom == a.Table { return -1 } case selectScope: if tagAtom != a.Optgroup && tagAtom != a.Option { return -1 } default: panic("unreachable") } } switch s { case defaultScope, listItemScope, buttonScope: for _, t := range defaultScopeStopTags[p.oe[i].Namespace] { if t == tagAtom { return -1 } } } } return -1 } // elementInScope is like popUntil, except that it doesn't modify the stack of // open elements. func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool { return p.indexOfElementInScope(s, matchTags...) != -1 } // clearStackToContext pops elements off the stack of open elements until a // scope-defined element is found. func (p *parser) clearStackToContext(s scope) { for i := len(p.oe) - 1; i >= 0; i-- { tagAtom := p.oe[i].DataAtom switch s { case tableScope: if tagAtom == a.Html || tagAtom == a.Table { p.oe = p.oe[:i+1] return } case tableRowScope: if tagAtom == a.Html || tagAtom == a.Tr { p.oe = p.oe[:i+1] return } case tableBodyScope: if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead { p.oe = p.oe[:i+1] return } default: panic("unreachable") } } } // generateImpliedEndTags pops nodes off the stack of open elements as long as // the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt. // If exceptions are specified, nodes with that name will not be popped off. func (p *parser) generateImpliedEndTags(exceptions ...string) { var i int loop: for i = len(p.oe) - 1; i >= 0; i-- { n := p.oe[i] if n.Type == ElementNode { switch n.DataAtom { case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt: for _, except := range exceptions { if n.Data == except { break loop } } continue } } break } p.oe = p.oe[:i+1] } // addChild adds a child node n to the top element, and pushes n onto the stack // of open elements if it is an element node. func (p *parser) addChild(n *Node) { if p.shouldFosterParent() { p.fosterParent(n) } else { p.top().AppendChild(n) } if n.Type == ElementNode { p.oe = append(p.oe, n) } } // shouldFosterParent returns whether the next node to be added should be // foster parented. func (p *parser) shouldFosterParent() bool { if p.fosterParenting { switch p.top().DataAtom { case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr: return true } } return false } // fosterParent adds a child node according to the foster parenting rules. // Section 12.2.5.3, "foster parenting". func (p *parser) fosterParent(n *Node) { var table, parent, prev *Node var i int for i = len(p.oe) - 1; i >= 0; i-- { if p.oe[i].DataAtom == a.Table { table = p.oe[i] break } } if table == nil { // The foster parent is the html element. parent = p.oe[0] } else { parent = table.Parent } if parent == nil { parent = p.oe[i-1] } if table != nil { prev = table.PrevSibling } else { prev = parent.LastChild } if prev != nil && prev.Type == TextNode && n.Type == TextNode { prev.Data += n.Data return } parent.InsertBefore(n, table) } // addText adds text to the preceding node if it is a text node, or else it // calls addChild with a new text node. func (p *parser) addText(text string) { if text == "" { return } if p.shouldFosterParent() { p.fosterParent(&Node{ Type: TextNode, Data: text, }) return } t := p.top() if n := t.LastChild; n != nil && n.Type == TextNode { n.Data += text return } p.addChild(&Node{ Type: TextNode, Data: text, }) } // addElement adds a child element based on the current token. func (p *parser) addElement() { p.addChild(&Node{ Type: ElementNode, DataAtom: p.tok.DataAtom, Data: p.tok.Data, Attr: p.tok.Attr, }) } // Section 12.2.3.3. func (p *parser) addFormattingElement() { tagAtom, attr := p.tok.DataAtom, p.tok.Attr p.addElement() // Implement the Noah's Ark clause, but with three per family instead of two. identicalElements := 0 findIdenticalElements: for i := len(p.afe) - 1; i >= 0; i-- { n := p.afe[i] if n.Type == scopeMarkerNode { break } if n.Type != ElementNode { continue } if n.Namespace != "" { continue } if n.DataAtom != tagAtom { continue } if len(n.Attr) != len(attr) { continue } compareAttributes: for _, t0 := range n.Attr { for _, t1 := range attr { if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val { // Found a match for this attribute, continue with the next attribute. continue compareAttributes } } // If we get here, there is no attribute that matches a. // Therefore the element is not identical to the new one. continue findIdenticalElements } identicalElements++ if identicalElements >= 3 { p.afe.remove(n) } } p.afe = append(p.afe, p.top()) } // Section 12.2.3.3. func (p *parser) clearActiveFormattingElements() { for { n := p.afe.pop() if len(p.afe) == 0 || n.Type == scopeMarkerNode { return } } } // Section 12.2.3.3. func (p *parser) reconstructActiveFormattingElements() { n := p.afe.top() if n == nil { return } if n.Type == scopeMarkerNode || p.oe.index(n) != -1 { return } i := len(p.afe) - 1 for n.Type != scopeMarkerNode && p.oe.index(n) == -1 { if i == 0 { i = -1 break } i-- n = p.afe[i] } for { i++ clone := p.afe[i].clone() p.addChild(clone) p.afe[i] = clone if i == len(p.afe)-1 { break } } } // Section 12.2.4. func (p *parser) acknowledgeSelfClosingTag() { p.hasSelfClosingToken = false } // An insertion mode (section 12.2.3.1) is the state transition function from // a particular state in the HTML5 parser's state machine. It updates the // parser's fields depending on parser.tok (where ErrorToken means EOF). // It returns whether the token was consumed. type insertionMode func(*parser) bool // setOriginalIM sets the insertion mode to return to after completing a text or // inTableText insertion mode. // Section 12.2.3.1, "using the rules for". func (p *parser) setOriginalIM() { if p.originalIM != nil { panic("html: bad parser state: originalIM was set twice") } p.originalIM = p.im } // Section 12.2.3.1, "reset the insertion mode". func (p *parser) resetInsertionMode() { for i := len(p.oe) - 1; i >= 0; i-- { n := p.oe[i] if i == 0 && p.context != nil { n = p.context } switch n.DataAtom { case a.Select: p.im = inSelectIM case a.Td, a.Th: p.im = inCellIM case a.Tr: p.im = inRowIM case a.Tbody, a.Thead, a.Tfoot: p.im = inTableBodyIM case a.Caption: p.im = inCaptionIM case a.Colgroup: p.im = inColumnGroupIM case a.Table: p.im = inTableIM case a.Head: p.im = inBodyIM case a.Body: p.im = inBodyIM case a.Frameset: p.im = inFramesetIM case a.Html: p.im = beforeHeadIM default: continue } return } p.im = inBodyIM } const whitespace = " \t\r\n\f" // Section 12.2.5.4.1. func initialIM(p *parser) bool { switch p.tok.Type { case TextToken: p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) if len(p.tok.Data) == 0 { // It was all whitespace, so ignore it. return true } case CommentToken: p.doc.AppendChild(&Node{ Type: CommentNode, Data: p.tok.Data, }) return true case DoctypeToken: n, quirks := parseDoctype(p.tok.Data) p.doc.AppendChild(n) p.quirks = quirks p.im = beforeHTMLIM return true } p.quirks = true p.im = beforeHTMLIM return false } // Section 12.2.5.4.2. func beforeHTMLIM(p *parser) bool { switch p.tok.Type { case DoctypeToken: // Ignore the token. return true case TextToken: p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) if len(p.tok.Data) == 0 { // It was all whitespace, so ignore it. return true } case StartTagToken: if p.tok.DataAtom == a.Html { p.addElement() p.im = beforeHeadIM return true } case EndTagToken: switch p.tok.DataAtom { case a.Head, a.Body, a.Html, a.Br: p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) return false default: // Ignore the token. return true } case CommentToken: p.doc.AppendChild(&Node{ Type: CommentNode, Data: p.tok.Data, }) return true } p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) return false } // Section 12.2.5.4.3. func beforeHeadIM(p *parser) bool { switch p.tok.Type { case TextToken: p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) if len(p.tok.Data) == 0 { // It was all whitespace, so ignore it. return true } case StartTagToken: switch p.tok.DataAtom { case a.Head: p.addElement() p.head = p.top() p.im = inHeadIM return true case a.Html: return inBodyIM(p) } case EndTagToken: switch p.tok.DataAtom { case a.Head, a.Body, a.Html, a.Br: p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) return false default: // Ignore the token. return true } case CommentToken: p.addChild(&Node{ Type: CommentNode, Data: p.tok.Data, }) return true case DoctypeToken: // Ignore the token. return true } p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) return false } // Section 12.2.5.4.4. func inHeadIM(p *parser) bool { switch p.tok.Type { case TextToken: s := strings.TrimLeft(p.tok.Data, whitespace) if len(s) < len(p.tok.Data) { // Add the initial whitespace to the current node. p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) if s == "" { return true } p.tok.Data = s } case StartTagToken: switch p.tok.DataAtom { case a.Html: return inBodyIM(p) case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta: p.addElement() p.oe.pop() p.acknowledgeSelfClosingTag() return true case a.Script, a.Title, a.Noscript, a.Noframes, a.Style: p.addElement() p.setOriginalIM() p.im = textIM return true case a.Head: // Ignore the token. return true } case EndTagToken: switch p.tok.DataAtom { case a.Head: n := p.oe.pop() if n.DataAtom != a.Head { panic("html: bad parser state: element not found, in the in-head insertion mode") } p.im = afterHeadIM return true case a.Body, a.Html, a.Br: p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) return false default: // Ignore the token. return true } case CommentToken: p.addChild(&Node{ Type: CommentNode, Data: p.tok.Data, }) return true case DoctypeToken: // Ignore the token. return true } p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) return false } // Section 12.2.5.4.6. func afterHeadIM(p *parser) bool { switch p.tok.Type { case TextToken: s := strings.TrimLeft(p.tok.Data, whitespace) if len(s) < len(p.tok.Data) { // Add the initial whitespace to the current node. p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) if s == "" { return true } p.tok.Data = s } case StartTagToken: switch p.tok.DataAtom { case a.Html: return inBodyIM(p) case a.Body: p.addElement() p.framesetOK = false p.im = inBodyIM return true case a.Frameset: p.addElement() p.im = inFramesetIM return true case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title: p.oe = append(p.oe, p.head) defer p.oe.remove(p.head) return inHeadIM(p) case a.Head: // Ignore the token. return true } case EndTagToken: switch p.tok.DataAtom { case a.Body, a.Html, a.Br: // Drop down to creating an implied tag. default: // Ignore the token. return true } case CommentToken: p.addChild(&Node{ Type: CommentNode, Data: p.tok.Data, }) return true case DoctypeToken: // Ignore the token. return true } p.parseImpliedToken(StartTagToken, a.Body, a.Body.String()) p.framesetOK = true return false } // copyAttributes copies attributes of src not found on dst to dst. func copyAttributes(dst *Node, src Token) { if len(src.Attr) == 0 { return } attr := map[string]string{} for _, t := range dst.Attr { attr[t.Key] = t.Val } for _, t := range src.Attr { if _, ok := attr[t.Key]; !ok { dst.Attr = append(dst.Attr, t) attr[t.Key] = t.Val } } } // Section 12.2.5.4.7. func inBodyIM(p *parser) bool { switch p.tok.Type { case TextToken: d := p.tok.Data switch n := p.oe.top(); n.DataAtom { case a.Pre, a.Listing: if n.FirstChild == nil { // Ignore a newline at the start of a
 block.
				if d != "" && d[0] == '\r' {
					d = d[1:]
				}
				if d != "" && d[0] == '\n' {
					d = d[1:]
				}
			}
		}
		d = strings.Replace(d, "\x00", "", -1)
		if d == "" {
			return true
		}
		p.reconstructActiveFormattingElements()
		p.addText(d)
		if p.framesetOK && strings.TrimLeft(d, whitespace) != "" {
			// There were non-whitespace characters inserted.
			p.framesetOK = false
		}
	case StartTagToken:
		switch p.tok.DataAtom {
		case a.Html:
			copyAttributes(p.oe[0], p.tok)
		case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
			return inHeadIM(p)
		case a.Body:
			if len(p.oe) >= 2 {
				body := p.oe[1]
				if body.Type == ElementNode && body.DataAtom == a.Body {
					p.framesetOK = false
					copyAttributes(body, p.tok)
				}
			}
		case a.Frameset:
			if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
				// Ignore the token.
				return true
			}
			body := p.oe[1]
			if body.Parent != nil {
				body.Parent.RemoveChild(body)
			}
			p.oe = p.oe[:1]
			p.addElement()
			p.im = inFramesetIM
			return true
		case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
			p.popUntil(buttonScope, a.P)
			p.addElement()
		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
			p.popUntil(buttonScope, a.P)
			switch n := p.top(); n.DataAtom {
			case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
				p.oe.pop()
			}
			p.addElement()
		case a.Pre, a.Listing:
			p.popUntil(buttonScope, a.P)
			p.addElement()
			// The newline, if any, will be dealt with by the TextToken case.
			p.framesetOK = false
		case a.Form:
			if p.form == nil {
				p.popUntil(buttonScope, a.P)
				p.addElement()
				p.form = p.top()
			}
		case a.Li:
			p.framesetOK = false
			for i := len(p.oe) - 1; i >= 0; i-- {
				node := p.oe[i]
				switch node.DataAtom {
				case a.Li:
					p.oe = p.oe[:i]
				case a.Address, a.Div, a.P:
					continue
				default:
					if !isSpecialElement(node) {
						continue
					}
				}
				break
			}
			p.popUntil(buttonScope, a.P)
			p.addElement()
		case a.Dd, a.Dt:
			p.framesetOK = false
			for i := len(p.oe) - 1; i >= 0; i-- {
				node := p.oe[i]
				switch node.DataAtom {
				case a.Dd, a.Dt:
					p.oe = p.oe[:i]
				case a.Address, a.Div, a.P:
					continue
				default:
					if !isSpecialElement(node) {
						continue
					}
				}
				break
			}
			p.popUntil(buttonScope, a.P)
			p.addElement()
		case a.Plaintext:
			p.popUntil(buttonScope, a.P)
			p.addElement()
		case a.Button:
			p.popUntil(defaultScope, a.Button)
			p.reconstructActiveFormattingElements()
			p.addElement()
			p.framesetOK = false
		case a.A:
			for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
				if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
					p.inBodyEndTagFormatting(a.A)
					p.oe.remove(n)
					p.afe.remove(n)
					break
				}
			}
			p.reconstructActiveFormattingElements()
			p.addFormattingElement()
		case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
			p.reconstructActiveFormattingElements()
			p.addFormattingElement()
		case a.Nobr:
			p.reconstructActiveFormattingElements()
			if p.elementInScope(defaultScope, a.Nobr) {
				p.inBodyEndTagFormatting(a.Nobr)
				p.reconstructActiveFormattingElements()
			}
			p.addFormattingElement()
		case a.Applet, a.Marquee, a.Object:
			p.reconstructActiveFormattingElements()
			p.addElement()
			p.afe = append(p.afe, &scopeMarker)
			p.framesetOK = false
		case a.Table:
			if !p.quirks {
				p.popUntil(buttonScope, a.P)
			}
			p.addElement()
			p.framesetOK = false
			p.im = inTableIM
			return true
		case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
			p.reconstructActiveFormattingElements()
			p.addElement()
			p.oe.pop()
			p.acknowledgeSelfClosingTag()
			if p.tok.DataAtom == a.Input {
				for _, t := range p.tok.Attr {
					if t.Key == "type" {
						if strings.ToLower(t.Val) == "hidden" {
							// Skip setting framesetOK = false
							return true
						}
					}
				}
			}
			p.framesetOK = false
		case a.Param, a.Source, a.Track:
			p.addElement()
			p.oe.pop()
			p.acknowledgeSelfClosingTag()
		case a.Hr:
			p.popUntil(buttonScope, a.P)
			p.addElement()
			p.oe.pop()
			p.acknowledgeSelfClosingTag()
			p.framesetOK = false
		case a.Image:
			p.tok.DataAtom = a.Img
			p.tok.Data = a.Img.String()
			return false
		case a.Isindex:
			if p.form != nil {
				// Ignore the token.
				return true
			}
			action := ""
			prompt := "This is a searchable index. Enter search keywords: "
			attr := []Attribute{{Key: "name", Val: "isindex"}}
			for _, t := range p.tok.Attr {
				switch t.Key {
				case "action":
					action = t.Val
				case "name":
					// Ignore the attribute.
				case "prompt":
					prompt = t.Val
				default:
					attr = append(attr, t)
				}
			}
			p.acknowledgeSelfClosingTag()
			p.popUntil(buttonScope, a.P)
			p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
			if action != "" {
				p.form.Attr = []Attribute{{Key: "action", Val: action}}
			}
			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
			p.parseImpliedToken(StartTagToken, a.Label, a.Label.String())
			p.addText(prompt)
			p.addChild(&Node{
				Type:     ElementNode,
				DataAtom: a.Input,
				Data:     a.Input.String(),
				Attr:     attr,
			})
			p.oe.pop()
			p.parseImpliedToken(EndTagToken, a.Label, a.Label.String())
			p.parseImpliedToken(StartTagToken, a.Hr, a.Hr.String())
			p.parseImpliedToken(EndTagToken, a.Form, a.Form.String())
		case a.Textarea:
			p.addElement()
			p.setOriginalIM()
			p.framesetOK = false
			p.im = textIM
		case a.Xmp:
			p.popUntil(buttonScope, a.P)
			p.reconstructActiveFormattingElements()
			p.framesetOK = false
			p.addElement()
			p.setOriginalIM()
			p.im = textIM
		case a.Iframe:
			p.framesetOK = false
			p.addElement()
			p.setOriginalIM()
			p.im = textIM
		case a.Noembed, a.Noscript:
			p.addElement()
			p.setOriginalIM()
			p.im = textIM
		case a.Select:
			p.reconstructActiveFormattingElements()
			p.addElement()
			p.framesetOK = false
			p.im = inSelectIM
			return true
		case a.Optgroup, a.Option:
			if p.top().DataAtom == a.Option {
				p.oe.pop()
			}
			p.reconstructActiveFormattingElements()
			p.addElement()
		case a.Rp, a.Rt:
			if p.elementInScope(defaultScope, a.Ruby) {
				p.generateImpliedEndTags()
			}
			p.addElement()
		case a.Math, a.Svg:
			p.reconstructActiveFormattingElements()
			if p.tok.DataAtom == a.Math {
				adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
			} else {
				adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
			}
			adjustForeignAttributes(p.tok.Attr)
			p.addElement()
			p.top().Namespace = p.tok.Data
			if p.hasSelfClosingToken {
				p.oe.pop()
				p.acknowledgeSelfClosingTag()
			}
			return true
		case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
			// Ignore the token.
		default:
			p.reconstructActiveFormattingElements()
			p.addElement()
		}
	case EndTagToken:
		switch p.tok.DataAtom {
		case a.Body:
			if p.elementInScope(defaultScope, a.Body) {
				p.im = afterBodyIM
			}
		case a.Html:
			if p.elementInScope(defaultScope, a.Body) {
				p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
				return false
			}
			return true
		case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
			p.popUntil(defaultScope, p.tok.DataAtom)
		case a.Form:
			node := p.form
			p.form = nil
			i := p.indexOfElementInScope(defaultScope, a.Form)
			if node == nil || i == -1 || p.oe[i] != node {
				// Ignore the token.
				return true
			}
			p.generateImpliedEndTags()
			p.oe.remove(node)
		case a.P:
			if !p.elementInScope(buttonScope, a.P) {
				p.parseImpliedToken(StartTagToken, a.P, a.P.String())
			}
			p.popUntil(buttonScope, a.P)
		case a.Li:
			p.popUntil(listItemScope, a.Li)
		case a.Dd, a.Dt:
			p.popUntil(defaultScope, p.tok.DataAtom)
		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
			p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
		case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
			p.inBodyEndTagFormatting(p.tok.DataAtom)
		case a.Applet, a.Marquee, a.Object:
			if p.popUntil(defaultScope, p.tok.DataAtom) {
				p.clearActiveFormattingElements()
			}
		case a.Br:
			p.tok.Type = StartTagToken
			return false
		default:
			p.inBodyEndTagOther(p.tok.DataAtom)
		}
	case CommentToken:
		p.addChild(&Node{
			Type: CommentNode,
			Data: p.tok.Data,
		})
	}

	return true
}

func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
	// This is the "adoption agency" algorithm, described at
	// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency

	// TODO: this is a fairly literal line-by-line translation of that algorithm.
	// Once the code successfully parses the comprehensive test suite, we should
	// refactor this code to be more idiomatic.

	// Steps 1-4. The outer loop.
	for i := 0; i < 8; i++ {
		// Step 5. Find the formatting element.
		var formattingElement *Node
		for j := len(p.afe) - 1; j >= 0; j-- {
			if p.afe[j].Type == scopeMarkerNode {
				break
			}
			if p.afe[j].DataAtom == tagAtom {
				formattingElement = p.afe[j]
				break
			}
		}
		if formattingElement == nil {
			p.inBodyEndTagOther(tagAtom)
			return
		}
		feIndex := p.oe.index(formattingElement)
		if feIndex == -1 {
			p.afe.remove(formattingElement)
			return
		}
		if !p.elementInScope(defaultScope, tagAtom) {
			// Ignore the tag.
			return
		}

		// Steps 9-10. Find the furthest block.
		var furthestBlock *Node
		for _, e := range p.oe[feIndex:] {
			if isSpecialElement(e) {
				furthestBlock = e
				break
			}
		}
		if furthestBlock == nil {
			e := p.oe.pop()
			for e != formattingElement {
				e = p.oe.pop()
			}
			p.afe.remove(e)
			return
		}

		// Steps 11-12. Find the common ancestor and bookmark node.
		commonAncestor := p.oe[feIndex-1]
		bookmark := p.afe.index(formattingElement)

		// Step 13. The inner loop. Find the lastNode to reparent.
		lastNode := furthestBlock
		node := furthestBlock
		x := p.oe.index(node)
		// Steps 13.1-13.2
		for j := 0; j < 3; j++ {
			// Step 13.3.
			x--
			node = p.oe[x]
			// Step 13.4 - 13.5.
			if p.afe.index(node) == -1 {
				p.oe.remove(node)
				continue
			}
			// Step 13.6.
			if node == formattingElement {
				break
			}
			// Step 13.7.
			clone := node.clone()
			p.afe[p.afe.index(node)] = clone
			p.oe[p.oe.index(node)] = clone
			node = clone
			// Step 13.8.
			if lastNode == furthestBlock {
				bookmark = p.afe.index(node) + 1
			}
			// Step 13.9.
			if lastNode.Parent != nil {
				lastNode.Parent.RemoveChild(lastNode)
			}
			node.AppendChild(lastNode)
			// Step 13.10.
			lastNode = node
		}

		// Step 14. Reparent lastNode to the common ancestor,
		// or for misnested table nodes, to the foster parent.
		if lastNode.Parent != nil {
			lastNode.Parent.RemoveChild(lastNode)
		}
		switch commonAncestor.DataAtom {
		case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
			p.fosterParent(lastNode)
		default:
			commonAncestor.AppendChild(lastNode)
		}

		// Steps 15-17. Reparent nodes from the furthest block's children
		// to a clone of the formatting element.
		clone := formattingElement.clone()
		reparentChildren(clone, furthestBlock)
		furthestBlock.AppendChild(clone)

		// Step 18. Fix up the list of active formatting elements.
		if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
			// Move the bookmark with the rest of the list.
			bookmark--
		}
		p.afe.remove(formattingElement)
		p.afe.insert(bookmark, clone)

		// Step 19. Fix up the stack of open elements.
		p.oe.remove(formattingElement)
		p.oe.insert(p.oe.index(furthestBlock)+1, clone)
	}
}

// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
// "Any other end tag" handling from 12.2.5.5 The rules for parsing tokens in foreign content
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
	for i := len(p.oe) - 1; i >= 0; i-- {
		if p.oe[i].DataAtom == tagAtom {
			p.oe = p.oe[:i]
			break
		}
		if isSpecialElement(p.oe[i]) {
			break
		}
	}
}

// Section 12.2.5.4.8.
func textIM(p *parser) bool {
	switch p.tok.Type {
	case ErrorToken:
		p.oe.pop()
	case TextToken:
		d := p.tok.Data
		if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil {
			// Ignore a newline at the start of a -->
#errors
#document
| 
|   
|   
|     -->
#errors
#document
| 
|   
|   
|     
#errors
Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE.
#document
| 
|   
|   
|     
#errors
Line: 1 Col: 9 Unexpected end tag (strong). Expected DOCTYPE.
Line: 1 Col: 9 Unexpected end tag (strong) after the (implied) root element.
Line: 1 Col: 13 Unexpected end tag (b) after the (implied) root element.
Line: 1 Col: 18 Unexpected end tag (em) after the (implied) root element.
Line: 1 Col: 22 Unexpected end tag (i) after the (implied) root element.
Line: 1 Col: 26 Unexpected end tag (u) after the (implied) root element.
Line: 1 Col: 35 Unexpected end tag (strike) after the (implied) root element.
Line: 1 Col: 39 Unexpected end tag (s) after the (implied) root element.
Line: 1 Col: 47 Unexpected end tag (blink) after the (implied) root element.
Line: 1 Col: 52 Unexpected end tag (tt) after the (implied) root element.
Line: 1 Col: 58 Unexpected end tag (pre) after the (implied) root element.
Line: 1 Col: 64 Unexpected end tag (big) after the (implied) root element.
Line: 1 Col: 72 Unexpected end tag (small) after the (implied) root element.
Line: 1 Col: 79 Unexpected end tag (font) after the (implied) root element.
Line: 1 Col: 88 Unexpected end tag (select) after the (implied) root element.
Line: 1 Col: 93 Unexpected end tag (h1) after the (implied) root element.
Line: 1 Col: 98 Unexpected end tag (h2) after the (implied) root element.
Line: 1 Col: 103 Unexpected end tag (h3) after the (implied) root element.
Line: 1 Col: 108 Unexpected end tag (h4) after the (implied) root element.
Line: 1 Col: 113 Unexpected end tag (h5) after the (implied) root element.
Line: 1 Col: 118 Unexpected end tag (h6) after the (implied) root element.
Line: 1 Col: 125 Unexpected end tag (body) after the (implied) root element.
Line: 1 Col: 130 Unexpected end tag (br). Treated as br element.
Line: 1 Col: 134 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm.
Line: 1 Col: 140 This element (img) has no end tag.
Line: 1 Col: 148 Unexpected end tag (title). Ignored.
Line: 1 Col: 155 Unexpected end tag (span). Ignored.
Line: 1 Col: 163 Unexpected end tag (style). Ignored.
Line: 1 Col: 172 Unexpected end tag (script). Ignored.
Line: 1 Col: 180 Unexpected end tag (table). Ignored.
Line: 1 Col: 185 Unexpected end tag (th). Ignored.
Line: 1 Col: 190 Unexpected end tag (td). Ignored.
Line: 1 Col: 195 Unexpected end tag (tr). Ignored.
Line: 1 Col: 203 This element (frame) has no end tag.
Line: 1 Col: 210 This element (area) has no end tag.
Line: 1 Col: 217 Unexpected end tag (link). Ignored.
Line: 1 Col: 225 This element (param) has no end tag.
Line: 1 Col: 230 This element (hr) has no end tag.
Line: 1 Col: 238 This element (input) has no end tag.
Line: 1 Col: 244 Unexpected end tag (col). Ignored.
Line: 1 Col: 251 Unexpected end tag (base). Ignored.
Line: 1 Col: 258 Unexpected end tag (meta). Ignored.
Line: 1 Col: 269 This element (basefont) has no end tag.
Line: 1 Col: 279 This element (bgsound) has no end tag.
Line: 1 Col: 287 This element (embed) has no end tag.
Line: 1 Col: 296 This element (spacer) has no end tag.
Line: 1 Col: 300 Unexpected end tag (p). Ignored.
Line: 1 Col: 305 End tag (dd) seen too early. Expected other end tag.
Line: 1 Col: 310 End tag (dt) seen too early. Expected other end tag.
Line: 1 Col: 320 Unexpected end tag (caption). Ignored.
Line: 1 Col: 331 Unexpected end tag (colgroup). Ignored.
Line: 1 Col: 339 Unexpected end tag (tbody). Ignored.
Line: 1 Col: 347 Unexpected end tag (tfoot). Ignored.
Line: 1 Col: 355 Unexpected end tag (thead). Ignored.
Line: 1 Col: 365 End tag (address) seen too early. Expected other end tag.
Line: 1 Col: 378 End tag (blockquote) seen too early. Expected other end tag.
Line: 1 Col: 387 End tag (center) seen too early. Expected other end tag.
Line: 1 Col: 393 Unexpected end tag (dir). Ignored.
Line: 1 Col: 399 End tag (div) seen too early. Expected other end tag.
Line: 1 Col: 404 End tag (dl) seen too early. Expected other end tag.
Line: 1 Col: 415 End tag (fieldset) seen too early. Expected other end tag.
Line: 1 Col: 425 End tag (listing) seen too early. Expected other end tag.
Line: 1 Col: 432 End tag (menu) seen too early. Expected other end tag.
Line: 1 Col: 437 End tag (ol) seen too early. Expected other end tag.
Line: 1 Col: 442 End tag (ul) seen too early. Expected other end tag.
Line: 1 Col: 447 End tag (li) seen too early. Expected other end tag.
Line: 1 Col: 454 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm.
Line: 1 Col: 460 This element (wbr) has no end tag.
Line: 1 Col: 476 End tag (button) seen too early. Expected other end tag.
Line: 1 Col: 486 End tag (marquee) seen too early. Expected other end tag.
Line: 1 Col: 495 End tag (object) seen too early. Expected other end tag.
Line: 1 Col: 513 Unexpected end tag (html). Ignored.
Line: 1 Col: 513 Unexpected end tag (frameset). Ignored.
Line: 1 Col: 520 Unexpected end tag (head). Ignored.
Line: 1 Col: 529 Unexpected end tag (iframe). Ignored.
Line: 1 Col: 537 This element (image) has no end tag.
Line: 1 Col: 547 This element (isindex) has no end tag.
Line: 1 Col: 557 Unexpected end tag (noembed). Ignored.
Line: 1 Col: 568 Unexpected end tag (noframes). Ignored.
Line: 1 Col: 579 Unexpected end tag (noscript). Ignored.
Line: 1 Col: 590 Unexpected end tag (optgroup). Ignored.
Line: 1 Col: 599 Unexpected end tag (option). Ignored.
Line: 1 Col: 611 Unexpected end tag (plaintext). Ignored.
Line: 1 Col: 622 Unexpected end tag (textarea). Ignored.
#document
| 
|   
|   
|     
|

#data

#errors Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. Line: 1 Col: 20 Unexpected end tag (strong) in table context caused voodoo mode. Line: 1 Col: 20 End tag (strong) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 24 Unexpected end tag (b) in table context caused voodoo mode. Line: 1 Col: 24 End tag (b) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 29 Unexpected end tag (em) in table context caused voodoo mode. Line: 1 Col: 29 End tag (em) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 33 Unexpected end tag (i) in table context caused voodoo mode. Line: 1 Col: 33 End tag (i) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 37 Unexpected end tag (u) in table context caused voodoo mode. Line: 1 Col: 37 End tag (u) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 46 Unexpected end tag (strike) in table context caused voodoo mode. Line: 1 Col: 46 End tag (strike) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 50 Unexpected end tag (s) in table context caused voodoo mode. Line: 1 Col: 50 End tag (s) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 58 Unexpected end tag (blink) in table context caused voodoo mode. Line: 1 Col: 58 Unexpected end tag (blink). Ignored. Line: 1 Col: 63 Unexpected end tag (tt) in table context caused voodoo mode. Line: 1 Col: 63 End tag (tt) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 69 Unexpected end tag (pre) in table context caused voodoo mode. Line: 1 Col: 69 End tag (pre) seen too early. Expected other end tag. Line: 1 Col: 75 Unexpected end tag (big) in table context caused voodoo mode. Line: 1 Col: 75 End tag (big) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 83 Unexpected end tag (small) in table context caused voodoo mode. Line: 1 Col: 83 End tag (small) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 90 Unexpected end tag (font) in table context caused voodoo mode. Line: 1 Col: 90 End tag (font) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 99 Unexpected end tag (select) in table context caused voodoo mode. Line: 1 Col: 99 Unexpected end tag (select). Ignored. Line: 1 Col: 104 Unexpected end tag (h1) in table context caused voodoo mode. Line: 1 Col: 104 End tag (h1) seen too early. Expected other end tag. Line: 1 Col: 109 Unexpected end tag (h2) in table context caused voodoo mode. Line: 1 Col: 109 End tag (h2) seen too early. Expected other end tag. Line: 1 Col: 114 Unexpected end tag (h3) in table context caused voodoo mode. Line: 1 Col: 114 End tag (h3) seen too early. Expected other end tag. Line: 1 Col: 119 Unexpected end tag (h4) in table context caused voodoo mode. Line: 1 Col: 119 End tag (h4) seen too early. Expected other end tag. Line: 1 Col: 124 Unexpected end tag (h5) in table context caused voodoo mode. Line: 1 Col: 124 End tag (h5) seen too early. Expected other end tag. Line: 1 Col: 129 Unexpected end tag (h6) in table context caused voodoo mode. Line: 1 Col: 129 End tag (h6) seen too early. Expected other end tag. Line: 1 Col: 136 Unexpected end tag (body) in the table row phase. Ignored. Line: 1 Col: 141 Unexpected end tag (br) in table context caused voodoo mode. Line: 1 Col: 141 Unexpected end tag (br). Treated as br element. Line: 1 Col: 145 Unexpected end tag (a) in table context caused voodoo mode. Line: 1 Col: 145 End tag (a) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 151 Unexpected end tag (img) in table context caused voodoo mode. Line: 1 Col: 151 This element (img) has no end tag. Line: 1 Col: 159 Unexpected end tag (title) in table context caused voodoo mode. Line: 1 Col: 159 Unexpected end tag (title). Ignored. Line: 1 Col: 166 Unexpected end tag (span) in table context caused voodoo mode. Line: 1 Col: 166 Unexpected end tag (span). Ignored. Line: 1 Col: 174 Unexpected end tag (style) in table context caused voodoo mode. Line: 1 Col: 174 Unexpected end tag (style). Ignored. Line: 1 Col: 183 Unexpected end tag (script) in table context caused voodoo mode. Line: 1 Col: 183 Unexpected end tag (script). Ignored. Line: 1 Col: 196 Unexpected end tag (th). Ignored. Line: 1 Col: 201 Unexpected end tag (td). Ignored. Line: 1 Col: 206 Unexpected end tag (tr). Ignored. Line: 1 Col: 214 This element (frame) has no end tag. Line: 1 Col: 221 This element (area) has no end tag. Line: 1 Col: 228 Unexpected end tag (link). Ignored. Line: 1 Col: 236 This element (param) has no end tag. Line: 1 Col: 241 This element (hr) has no end tag. Line: 1 Col: 249 This element (input) has no end tag. Line: 1 Col: 255 Unexpected end tag (col). Ignored. Line: 1 Col: 262 Unexpected end tag (base). Ignored. Line: 1 Col: 269 Unexpected end tag (meta). Ignored. Line: 1 Col: 280 This element (basefont) has no end tag. Line: 1 Col: 290 This element (bgsound) has no end tag. Line: 1 Col: 298 This element (embed) has no end tag. Line: 1 Col: 307 This element (spacer) has no end tag. Line: 1 Col: 311 Unexpected end tag (p). Ignored. Line: 1 Col: 316 End tag (dd) seen too early. Expected other end tag. Line: 1 Col: 321 End tag (dt) seen too early. Expected other end tag. Line: 1 Col: 331 Unexpected end tag (caption). Ignored. Line: 1 Col: 342 Unexpected end tag (colgroup). Ignored. Line: 1 Col: 350 Unexpected end tag (tbody). Ignored. Line: 1 Col: 358 Unexpected end tag (tfoot). Ignored. Line: 1 Col: 366 Unexpected end tag (thead). Ignored. Line: 1 Col: 376 End tag (address) seen too early. Expected other end tag. Line: 1 Col: 389 End tag (blockquote) seen too early. Expected other end tag. Line: 1 Col: 398 End tag (center) seen too early. Expected other end tag. Line: 1 Col: 404 Unexpected end tag (dir). Ignored. Line: 1 Col: 410 End tag (div) seen too early. Expected other end tag. Line: 1 Col: 415 End tag (dl) seen too early. Expected other end tag. Line: 1 Col: 426 End tag (fieldset) seen too early. Expected other end tag. Line: 1 Col: 436 End tag (listing) seen too early. Expected other end tag. Line: 1 Col: 443 End tag (menu) seen too early. Expected other end tag. Line: 1 Col: 448 End tag (ol) seen too early. Expected other end tag. Line: 1 Col: 453 End tag (ul) seen too early. Expected other end tag. Line: 1 Col: 458 End tag (li) seen too early. Expected other end tag. Line: 1 Col: 465 End tag (nobr) violates step 1, paragraph 1 of the adoption agency algorithm. Line: 1 Col: 471 This element (wbr) has no end tag. Line: 1 Col: 487 End tag (button) seen too early. Expected other end tag. Line: 1 Col: 497 End tag (marquee) seen too early. Expected other end tag. Line: 1 Col: 506 End tag (object) seen too early. Expected other end tag. Line: 1 Col: 524 Unexpected end tag (html). Ignored. Line: 1 Col: 524 Unexpected end tag (frameset). Ignored. Line: 1 Col: 531 Unexpected end tag (head). Ignored. Line: 1 Col: 540 Unexpected end tag (iframe). Ignored. Line: 1 Col: 548 This element (image) has no end tag. Line: 1 Col: 558 This element (isindex) has no end tag. Line: 1 Col: 568 Unexpected end tag (noembed). Ignored. Line: 1 Col: 579 Unexpected end tag (noframes). Ignored. Line: 1 Col: 590 Unexpected end tag (noscript). Ignored. Line: 1 Col: 601 Unexpected end tag (optgroup). Ignored. Line: 1 Col: 610 Unexpected end tag (option). Ignored. Line: 1 Col: 622 Unexpected end tag (plaintext). Ignored. Line: 1 Col: 633 Unexpected end tag (textarea). Ignored. #document | | | |
| | | |

#data #errors Line: 1 Col: 10 Unexpected start tag (frameset). Expected DOCTYPE. Line: 1 Col: 10 Expected closing tag. Unexpected end of file. #document | | | golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/testdata/webkit/tests10.dat000066400000000000000000000333351264464372400265060ustar00rootroot00000000000000#data #errors #document | | | | | #data a #errors 29: Bogus comment #document | | | | | | #data #errors #document | | | | | #data #errors 35: Stray “svg†start tag. 42: Stray end tag “svg†#document | | | | | #errors 43: Stray “svg†start tag. 50: Stray end tag “svg†#document | | | | |

#errors 34: Start tag “svg†seen in “tableâ€. 41: Stray end tag “svgâ€. #document | | | | | | #data
foo
#errors 34: Start tag “svg†seen in “tableâ€. 46: Stray end tag “gâ€. 53: Stray end tag “svgâ€. #document | | | | | | | "foo" | #data
foobar
#errors 34: Start tag “svg†seen in “tableâ€. 46: Stray end tag “gâ€. 58: Stray end tag “gâ€. 65: Stray end tag “svgâ€. #document | | | | | | | "foo" | | "bar" | #data
foobar
#errors 41: Start tag “svg†seen in “tableâ€. 53: Stray end tag “gâ€. 65: Stray end tag “gâ€. 72: Stray end tag “svgâ€. #document | | | | | | | "foo" | | "bar" | | #data
foobar
#errors 45: Start tag “svg†seen in “tableâ€. 57: Stray end tag “gâ€. 69: Stray end tag “gâ€. 76: Stray end tag “svgâ€. #document | | | | | | | "foo" | | "bar" | | | #data
foobar
#errors #document | | | | | | | |
| | | "foo" | | "bar" #data
foobar

baz

#errors #document | | | | | | | |
| | | "foo" | | "bar" |

| "baz" #data
foobar

baz

#errors #document | | | | | |
| | | "foo" | | "bar" |

| "baz" #data
foobar

baz

quux #errors 70: HTML start tag “p†in a foreign namespace context. 81: “table†closed but “caption†was still open. #document | | | | | |
| | | "foo" | | "bar" |

| "baz" |

| "quux" #data
foobarbaz

quux #errors 78: “table†closed but “caption†was still open. 78: Unclosed elements on stack. #document | | | | | |
| | | "foo" | | "bar" | "baz" |

| "quux" #data foobar

baz

quux #errors 44: Start tag “svg†seen in “tableâ€. 56: Stray end tag “gâ€. 68: Stray end tag “gâ€. 71: HTML start tag “p†in a foreign namespace context. 71: Start tag “p†seen in “tableâ€. #document | | | | | | | "foo" | | "bar" |

| "baz" | | |

| "quux" #data

quux #errors 50: Stray “svg†start tag. 54: Stray “g†start tag. 62: Stray end tag “g†66: Stray “g†start tag. 74: Stray end tag “g†77: Stray “p†start tag. 88: “table†end tag with “select†open. #document | | | | | | | |
|

quux #errors 36: Start tag “select†seen in “tableâ€. 42: Stray “svg†start tag. 46: Stray “g†start tag. 54: Stray end tag “g†58: Stray “g†start tag. 66: Stray end tag “g†69: Stray “p†start tag. 80: “table†end tag with “select†open. #document | | | | | |

| "quux" #data foobar

baz #errors 41: Stray “svg†start tag. 68: HTML start tag “p†in a foreign namespace context. #document | | | | | | | "foo" | | "bar" |

| "baz" #data foobar

baz #errors 34: Stray “svg†start tag. 61: HTML start tag “p†in a foreign namespace context. #document | | | | | | | "foo" | | "bar" |

| "baz" #data

#errors 31: Stray “svg†start tag. 35: Stray “g†start tag. 40: Stray end tag “g†44: Stray “g†start tag. 49: Stray end tag “g†52: Stray “p†start tag. 58: Stray “span†start tag. 58: End of file seen and there were open elements. #document | | | | #data

#errors 42: Stray “svg†start tag. 46: Stray “g†start tag. 51: Stray end tag “g†55: Stray “g†start tag. 60: Stray end tag “g†63: Stray “p†start tag. 69: Stray “span†start tag. #document | | | | #data #errors #document | | | | | xlink:href="foo" | | xlink href="foo" #data #errors #document | | | | | xlink:href="foo" | xml:lang="en" | | | xlink href="foo" | xml lang="en" #data #errors #document | | | | | xlink:href="foo" | xml:lang="en" | | | xlink href="foo" | xml lang="en" #data bar #errors #document | | | | | xlink:href="foo" | xml:lang="en" | | | xlink href="foo" | xml lang="en" | "bar" #data #errors #document | | | | #data

a #errors #document | | | |
| | "a" #data
a #errors #document | | | |
| | | "a" #data
#errors #document | | | |
| | | #data
a #errors #document | | | |
| | | | | "a" #data

a #errors #document | | | |

| | | |

| "a" #data
    a #errors 40: HTML start tag “ul†in a foreign namespace context. 41: End of file in a foreign namespace context. #document | | | | | | |
    | |
      | "a" #data
        a #errors 35: HTML start tag “ul†in a foreign namespace context. 36: End of file in a foreign namespace context. #document | | | | | | | |
          | "a" #data

          #errors #document | | | | |

          | | |

          #data

          #errors #document | | | | |

          | | |

          #data

          #errors #document | | | |

          | | | |

          |

          #data
          #errors #document | | | | | |
          | |
          | | #data
          #errors #document | | | | | | | |
          |
          | #data #errors #document | | | | | | #data

#errors #document | | | | |
| | #data #errors #document | | | | | | #data #errors #document | | | | | | #data #errors #document | | | | | | #data #errors #document | | | | | | #data #errors #document | | | | | | #data #errors #document | | | | | | #data #errors #document | | | | | | #data #errors #document | | | | | | #data #errors #document | | | | | | #data #errors #document | | | | | | #data #errors #document | | | | | | | #data
#errors #document | | | | | | | |
| | | | | #data #errors #document | | | | | | | | | | | | | | ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/testdata/webkit/tests11.dat��������������������0000664�0000000�0000000�00000041375�12644643724�0026512�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#data #errors #document | | | | | | attributeName="" | attributeType="" | baseFrequency="" | baseProfile="" | calcMode="" | clipPathUnits="" | contentScriptType="" | contentStyleType="" | diffuseConstant="" | edgeMode="" | externalResourcesRequired="" | filterRes="" | filterUnits="" | glyphRef="" | gradientTransform="" | gradientUnits="" | kernelMatrix="" | kernelUnitLength="" | keyPoints="" | keySplines="" | keyTimes="" | lengthAdjust="" | limitingConeAngle="" | markerHeight="" | markerUnits="" | markerWidth="" | maskContentUnits="" | maskUnits="" | numOctaves="" | pathLength="" | patternContentUnits="" | patternTransform="" | patternUnits="" | pointsAtX="" | pointsAtY="" | pointsAtZ="" | preserveAlpha="" | preserveAspectRatio="" | primitiveUnits="" | refX="" | refY="" | repeatCount="" | repeatDur="" | requiredExtensions="" | requiredFeatures="" | specularConstant="" | specularExponent="" | spreadMethod="" | startOffset="" | stdDeviation="" | stitchTiles="" | surfaceScale="" | systemLanguage="" | tableValues="" | targetX="" | targetY="" | textLength="" | viewBox="" | viewTarget="" | xChannelSelector="" | yChannelSelector="" | zoomAndPan="" #data #errors #document | | | | | | attributeName="" | attributeType="" | baseFrequency="" | baseProfile="" | calcMode="" | clipPathUnits="" | contentScriptType="" | contentStyleType="" | diffuseConstant="" | edgeMode="" | externalResourcesRequired="" | filterRes="" | filterUnits="" | glyphRef="" | gradientTransform="" | gradientUnits="" | kernelMatrix="" | kernelUnitLength="" | keyPoints="" | keySplines="" | keyTimes="" | lengthAdjust="" | limitingConeAngle="" | markerHeight="" | markerUnits="" | markerWidth="" | maskContentUnits="" | maskUnits="" | numOctaves="" | pathLength="" | patternContentUnits="" | patternTransform="" | patternUnits="" | pointsAtX="" | pointsAtY="" | pointsAtZ="" | preserveAlpha="" | preserveAspectRatio="" | primitiveUnits="" | refX="" | refY="" | repeatCount="" | repeatDur="" | requiredExtensions="" | requiredFeatures="" | specularConstant="" | specularExponent="" | spreadMethod="" | startOffset="" | stdDeviation="" | stitchTiles="" | surfaceScale="" | systemLanguage="" | tableValues="" | targetX="" | targetY="" | textLength="" | viewBox="" | viewTarget="" | xChannelSelector="" | yChannelSelector="" | zoomAndPan="" #data #errors #document | | | | | | attributeName="" | attributeType="" | baseFrequency="" | baseProfile="" | calcMode="" | clipPathUnits="" | contentScriptType="" | contentStyleType="" | diffuseConstant="" | edgeMode="" | externalResourcesRequired="" | filterRes="" | filterUnits="" | glyphRef="" | gradientTransform="" | gradientUnits="" | kernelMatrix="" | kernelUnitLength="" | keyPoints="" | keySplines="" | keyTimes="" | lengthAdjust="" | limitingConeAngle="" | markerHeight="" | markerUnits="" | markerWidth="" | maskContentUnits="" | maskUnits="" | numOctaves="" | pathLength="" | patternContentUnits="" | patternTransform="" | patternUnits="" | pointsAtX="" | pointsAtY="" | pointsAtZ="" | preserveAlpha="" | preserveAspectRatio="" | primitiveUnits="" | refX="" | refY="" | repeatCount="" | repeatDur="" | requiredExtensions="" | requiredFeatures="" | specularConstant="" | specularExponent="" | spreadMethod="" | startOffset="" | stdDeviation="" | stitchTiles="" | surfaceScale="" | systemLanguage="" | tableValues="" | targetX="" | targetY="" | textLength="" | viewBox="" | viewTarget="" | xChannelSelector="" | yChannelSelector="" | zoomAndPan="" #data #errors #document | | | | | | attributename="" | attributetype="" | basefrequency="" | baseprofile="" | calcmode="" | clippathunits="" | contentscripttype="" | contentstyletype="" | diffuseconstant="" | edgemode="" | externalresourcesrequired="" | filterres="" | filterunits="" | glyphref="" | gradienttransform="" | gradientunits="" | kernelmatrix="" | kernelunitlength="" | keypoints="" | keysplines="" | keytimes="" | lengthadjust="" | limitingconeangle="" | markerheight="" | markerunits="" | markerwidth="" | maskcontentunits="" | maskunits="" | numoctaves="" | pathlength="" | patterncontentunits="" | patterntransform="" | patternunits="" | pointsatx="" | pointsaty="" | pointsatz="" | preservealpha="" | preserveaspectratio="" | primitiveunits="" | refx="" | refy="" | repeatcount="" | repeatdur="" | requiredextensions="" | requiredfeatures="" | specularconstant="" | specularexponent="" | spreadmethod="" | startoffset="" | stddeviation="" | stitchtiles="" | surfacescale="" | systemlanguage="" | tablevalues="" | targetx="" | targety="" | textlength="" | viewbox="" | viewtarget="" | xchannelselector="" | ychannelselector="" | zoomandpan="" #data #errors #document | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | #data #errors #document | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | #data #errors #document | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | #data #errors #document | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | #data #errors #document | | | | | | �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/testdata/webkit/tests12.dat��������������������0000664�0000000�0000000�00000003114�12644643724�0026500�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#data

foobazeggs

spam

quuxbar #errors #document | | | | |

| "foo" | | | | "baz" | | | | | "eggs" | | |

| "spam" | | | |
| | | "quux" | "bar" #data foobazeggs

spam
quuxbar #errors #document | | | | | "foo" | | | | "baz" | | | | | "eggs" | | |

| "spam" | | | |
| | | "quux" | "bar" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/testdata/webkit/tests14.dat��������������������0000664�0000000�0000000�00000002045�12644643724�0026504�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#data #errors #document | | | | | #data #errors #document | | | | | | #data #errors 15: Unexpected start tag html #document | | | abc:def="gh" | | | #data #errors 15: Unexpected start tag html #document | | | xml:lang="bar" | | #data #errors #document | | | 123="456" | | #data #errors #document | | | 123="456" | 789="012" | | #data #errors #document | | | | | 789="012" golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/testdata/webkit/tests15.dat000066400000000000000000000100571264464372400265070ustar00rootroot00000000000000#data

X #errors Line: 1 Col: 31 Unexpected end tag (p). Ignored. Line: 1 Col: 36 Expected closing tag. Unexpected end of file. #document | | | | |

| | | | | | | " " |

| "X" #data

X #errors Line: 1 Col: 3 Unexpected start tag (p). Expected DOCTYPE. Line: 1 Col: 16 Unexpected end tag (p). Ignored. Line: 2 Col: 4 Expected closing tag. Unexpected end of file. #document | | | |

| | | | | | | " " |

| "X" #data #errors Line: 1 Col: 22 Unexpected end tag (html) after the (implied) root element. #document | | | | | " " #data #errors Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element. #document | | | | | #data #errors Line: 1 Col: 6 Unexpected start tag (html). Expected DOCTYPE. Line: 1 Col: 13 Unexpected end tag (html) after the (implied) root element. #document | | | | #data X #errors Line: 1 Col: 22 Unexpected end tag (body) after the (implied) root element. #document | | | | | | "X" #data <!doctype html><table> X<meta></table> #errors Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode. Line: 1 Col: 30 Unexpected start tag (meta) in table context caused voodoo mode. #document | <!DOCTYPE html> | <html> | <head> | <body> | " X" | <meta> | <table> #data <!doctype html><table> x</table> #errors Line: 1 Col: 24 Unexpected non-space characters in table context caused voodoo mode. #document | <!DOCTYPE html> | <html> | <head> | <body> | " x" | <table> #data <!doctype html><table> x </table> #errors Line: 1 Col: 25 Unexpected non-space characters in table context caused voodoo mode. #document | <!DOCTYPE html> | <html> | <head> | <body> | " x " | <table> #data <!doctype html><table><tr> x</table> #errors Line: 1 Col: 28 Unexpected non-space characters in table context caused voodoo mode. #document | <!DOCTYPE html> | <html> | <head> | <body> | " x" | <table> | <tbody> | <tr> #data <!doctype html><table>X<style> <tr>x </style> </table> #errors Line: 1 Col: 23 Unexpected non-space characters in table context caused voodoo mode. #document | <!DOCTYPE html> | <html> | <head> | <body> | "X" | <table> | <style> | " <tr>x " | " " #data <!doctype html><div><table><a>foo</a> <tr><td>bar</td> </tr></table></div> #errors Line: 1 Col: 30 Unexpected start tag (a) in table context caused voodoo mode. Line: 1 Col: 37 Unexpected end tag (a) in table context caused voodoo mode. #document | <!DOCTYPE html> | <html> | <head> | <body> | <div> | <a> | "foo" | <table> | " " | <tbody> | <tr> | <td> | "bar" | " " #data <frame></frame></frame><frameset><frame><frameset><frame></frameset><noframes></frameset><noframes> #errors 6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>â€. 13: Stray start tag “frameâ€. 21: Stray end tag “frameâ€. 29: Stray end tag “frameâ€. 39: “frameset†start tag after “body†already open. 105: End of file seen inside an [R]CDATA element. 105: End of file seen and there were open elements. XXX: These errors are wrong, please fix me! #document | <html> | <head> | <frameset> | <frame> | <frameset> | <frame> | <noframes> | "</frameset><noframes>" #data <!DOCTYPE html><object></html> #errors 1: Expected closing tag. Unexpected end of file #document | <!DOCTYPE html> | <html> | <head> | <body> | <object> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/testdata/webkit/tests16.dat��������������������0000664�0000000�0000000�00000125251�12644643724�0026513�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#data <!doctype html><script> #errors Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | <body> #data <!doctype html><script>a #errors Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "a" | <body> #data <!doctype html><script>< #errors Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<" | <body> #data <!doctype html><script></ #errors Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</" | <body> #data <!doctype html><script></S #errors Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</S" | <body> #data <!doctype html><script></SC #errors Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</SC" | <body> #data <!doctype html><script></SCR #errors Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</SCR" | <body> #data <!doctype html><script></SCRI #errors Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</SCRI" | <body> #data <!doctype html><script></SCRIP #errors Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</SCRIP" | <body> #data <!doctype html><script></SCRIPT #errors Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</SCRIPT" | <body> #data <!doctype html><script></SCRIPT #errors Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | <body> #data <!doctype html><script></s #errors Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</s" | <body> #data <!doctype html><script></sc #errors Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</sc" | <body> #data <!doctype html><script></scr #errors Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</scr" | <body> #data <!doctype html><script></scri #errors Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</scri" | <body> #data <!doctype html><script></scrip #errors Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</scrip" | <body> #data <!doctype html><script></script #errors Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "</script" | <body> #data <!doctype html><script></script #errors Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | <body> #data <!doctype html><script><! #errors Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!" | <body> #data <!doctype html><script><!a #errors Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!a" | <body> #data <!doctype html><script><!- #errors Line: 1 Col: 26 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!-" | <body> #data <!doctype html><script><!-a #errors Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!-a" | <body> #data <!doctype html><script><!-- #errors Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--" | <body> #data <!doctype html><script><!--a #errors Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--a" | <body> #data <!doctype html><script><!--< #errors Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<" | <body> #data <!doctype html><script><!--<a #errors Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<a" | <body> #data <!doctype html><script><!--</ #errors Line: 1 Col: 27 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--</" | <body> #data <!doctype html><script><!--</script #errors Line: 1 Col: 35 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--</script" | <body> #data <!doctype html><script><!--</script #errors Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--" | <body> #data <!doctype html><script><!--<s #errors Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<s" | <body> #data <!doctype html><script><!--<script #errors Line: 1 Col: 34 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script" | <body> #data <!doctype html><script><!--<script #errors Line: 1 Col: 35 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script " | <body> #data <!doctype html><script><!--<script < #errors Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script <" | <body> #data <!doctype html><script><!--<script <a #errors Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script <a" | <body> #data <!doctype html><script><!--<script </ #errors Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </" | <body> #data <!doctype html><script><!--<script </s #errors Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </s" | <body> #data <!doctype html><script><!--<script </script #errors Line: 1 Col: 43 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script" | <body> #data <!doctype html><script><!--<script </scripta #errors Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </scripta" | <body> #data <!doctype html><script><!--<script </script #errors Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script " | <body> #data <!doctype html><script><!--<script </script> #errors Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script>" | <body> #data <!doctype html><script><!--<script </script/ #errors Line: 1 Col: 44 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script/" | <body> #data <!doctype html><script><!--<script </script < #errors Line: 1 Col: 45 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script <" | <body> #data <!doctype html><script><!--<script </script <a #errors Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script <a" | <body> #data <!doctype html><script><!--<script </script </ #errors Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script </" | <body> #data <!doctype html><script><!--<script </script </script #errors Line: 1 Col: 52 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script </script" | <body> #data <!doctype html><script><!--<script </script </script #errors Line: 1 Col: 53 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script " | <body> #data <!doctype html><script><!--<script </script </script/ #errors Line: 1 Col: 53 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script " | <body> #data <!doctype html><script><!--<script </script </script> #errors #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script </script " | <body> #data <!doctype html><script><!--<script - #errors Line: 1 Col: 36 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script -" | <body> #data <!doctype html><script><!--<script -a #errors Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script -a" | <body> #data <!doctype html><script><!--<script -< #errors Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script -<" | <body> #data <!doctype html><script><!--<script -- #errors Line: 1 Col: 37 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script --" | <body> #data <!doctype html><script><!--<script --a #errors Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script --a" | <body> #data <!doctype html><script><!--<script --< #errors Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script --<" | <body> #data <!doctype html><script><!--<script --> #errors Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script -->" | <body> #data <!doctype html><script><!--<script -->< #errors Line: 1 Col: 39 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script --><" | <body> #data <!doctype html><script><!--<script --></ #errors Line: 1 Col: 40 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script --></" | <body> #data <!doctype html><script><!--<script --></script #errors Line: 1 Col: 46 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script --></script" | <body> #data <!doctype html><script><!--<script --></script #errors Line: 1 Col: 47 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script -->" | <body> #data <!doctype html><script><!--<script --></script/ #errors Line: 1 Col: 47 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script -->" | <body> #data <!doctype html><script><!--<script --></script> #errors #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script -->" | <body> #data <!doctype html><script><!--<script><\/script>--></script> #errors #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script><\/script>-->" | <body> #data <!doctype html><script><!--<script></scr'+'ipt>--></script> #errors #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script></scr'+'ipt>-->" | <body> #data <!doctype html><script><!--<script></script><script></script></script> #errors #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script></script><script></script>" | <body> #data <!doctype html><script><!--<script></script><script></script>--><!--</script> #errors #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script></script><script></script>--><!--" | <body> #data <!doctype html><script><!--<script></script><script></script>-- ></script> #errors #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script></script><script></script>-- >" | <body> #data <!doctype html><script><!--<script></script><script></script>- -></script> #errors #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script></script><script></script>- ->" | <body> #data <!doctype html><script><!--<script></script><script></script>- - ></script> #errors #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script></script><script></script>- - >" | <body> #data <!doctype html><script><!--<script></script><script></script>-></script> #errors #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script></script><script></script>->" | <body> #data <!doctype html><script><!--<script>--!></script>X #errors Line: 1 Col: 49 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script>--!></script>X" | <body> #data <!doctype html><script><!--<scr'+'ipt></script>--></script> #errors Line: 1 Col: 59 Unexpected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<scr'+'ipt>" | <body> | "-->" #data <!doctype html><script><!--<script></scr'+'ipt></script>X #errors Line: 1 Col: 57 Unexpected end of file. Expected end tag (script). #document | <!DOCTYPE html> | <html> | <head> | <script> | "<!--<script></scr'+'ipt></script>X" | <body> #data <!doctype html><style><!--<style></style>--></style> #errors Line: 1 Col: 52 Unexpected end tag (style). #document | <!DOCTYPE html> | <html> | <head> | <style> | "<!--<style>" | <body> | "-->" #data <!doctype html><style><!--</style>X #errors #document | <!DOCTYPE html> | <html> | <head> | <style> | "<!--" | <body> | "X" #data <!doctype html><style><!--...</style>...--></style> #errors Line: 1 Col: 51 Unexpected end tag (style). #document | <!DOCTYPE html> | <html> | <head> | <style> | "<!--..." | <body> | "...-->" #data <!doctype html><style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X #errors #document | <!DOCTYPE html> | <html> | <head> | <style> | "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>" | <body> | "X" #data <!doctype html><style><!--...<style><!--...--!></style>--></style> #errors Line: 1 Col: 66 Unexpected end tag (style). #document | <!DOCTYPE html> | <html> | <head> | <style> | "<!--...<style><!--...--!>" | <body> | "-->" #data <!doctype html><style><!--...</style><!-- --><style>@import ...</style> #errors #document | <!DOCTYPE html> | <html> | <head> | <style> | "<!--..." | <!-- --> | <style> | "@import ..." | <body> #data <!doctype html><style>...<style><!--...</style><!-- --></style> #errors Line: 1 Col: 63 Unexpected end tag (style). #document | <!DOCTYPE html> | <html> | <head> | <style> | "...<style><!--..." | <!-- --> | <body> #data <!doctype html><style>...<!--[if IE]><style>...</style>X #errors #document | <!DOCTYPE html> | <html> | <head> | <style> | "...<!--[if IE]><style>..." | <body> | "X" #data <!doctype html><title><!--<title>--> #errors Line: 1 Col: 52 Unexpected end tag (title). #document | | | | | "<!--<title>" | <body> | "-->" #data <!doctype html><title></title> #errors #document | | | | | "" | #data foo/title><link></head><body>X #errors Line: 1 Col: 52 Unexpected end of file. Expected end tag (title). #document | <!DOCTYPE html> | <html> | <head> | <title> | "foo/title><link></head><body>X" | <body> #data <!doctype html><noscript><!--<noscript></noscript>--></noscript> #errors Line: 1 Col: 64 Unexpected end tag (noscript). #document | <!DOCTYPE html> | <html> | <head> | <noscript> | "<!--<noscript>" | <body> | "-->" #data <!doctype html><noscript><!--</noscript>X<noscript>--></noscript> #errors #document | <!DOCTYPE html> | <html> | <head> | <noscript> | "<!--" | <body> | "X" | <noscript> | "-->" #data <!doctype html><noscript><iframe></noscript>X #errors #document | <!DOCTYPE html> | <html> | <head> | <noscript> | "<iframe>" | <body> | "X" #data <!doctype html><noframes><!--<noframes></noframes>--></noframes> #errors Line: 1 Col: 64 Unexpected end tag (noframes). #document | <!DOCTYPE html> | <html> | <head> | <noframes> | "<!--<noframes>" | <body> | "-->" #data <!doctype html><noframes><body><script><!--...</script></body></noframes></html> #errors #document | <!DOCTYPE html> | <html> | <head> | <noframes> | "<body><script><!--...</script></body>" | <body> #data <!doctype html><textarea><!--<textarea></textarea>--></textarea> #errors Line: 1 Col: 64 Unexpected end tag (textarea). #document | <!DOCTYPE html> | <html> | <head> | <body> | <textarea> | "<!--<textarea>" | "-->" #data <!doctype html><textarea></textarea></textarea> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <textarea> | "</textarea>" #data <!doctype html><textarea><</textarea> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <textarea> | "<" #data <!doctype html><textarea>a<b</textarea> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <textarea> | "a<b" #data <!doctype html><iframe><!--<iframe></iframe>--></iframe> #errors Line: 1 Col: 56 Unexpected end tag (iframe). #document | <!DOCTYPE html> | <html> | <head> | <body> | <iframe> | "<!--<iframe>" | "-->" #data <!doctype html><iframe>...<!--X->...<!--/X->...</iframe> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <iframe> | "...<!--X->...<!--/X->..." #data <!doctype html><xmp><!--<xmp></xmp>--></xmp> #errors Line: 1 Col: 44 Unexpected end tag (xmp). #document | <!DOCTYPE html> | <html> | <head> | <body> | <xmp> | "<!--<xmp>" | "-->" #data <!doctype html><noembed><!--<noembed></noembed>--></noembed> #errors Line: 1 Col: 60 Unexpected end tag (noembed). #document | <!DOCTYPE html> | <html> | <head> | <body> | <noembed> | "<!--<noembed>" | "-->" #data <script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 8 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | <body> #data <script>a #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 9 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "a" | <body> #data <script>< #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 9 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<" | <body> #data <script></ #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 10 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</" | <body> #data <script></S #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</S" | <body> #data <script></SC #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</SC" | <body> #data <script></SCR #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</SCR" | <body> #data <script></SCRI #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</SCRI" | <body> #data <script></SCRIP #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 15 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</SCRIP" | <body> #data <script></SCRIPT #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 16 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</SCRIPT" | <body> #data <script></SCRIPT #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 17 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | <body> #data <script></s #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</s" | <body> #data <script></sc #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</sc" | <body> #data <script></scr #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</scr" | <body> #data <script></scri #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</scri" | <body> #data <script></scrip #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 15 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</scrip" | <body> #data <script></script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 16 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</script" | <body> #data <script></script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 17 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | <body> #data <script><! #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 10 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!" | <body> #data <script><!a #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!a" | <body> #data <script><!- #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!-" | <body> #data <script><!-a #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!-a" | <body> #data <script><!-- #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 12 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--" | <body> #data <script><!--a #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--a" | <body> #data <script><!--< #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 13 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<" | <body> #data <script><!--<a #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<a" | <body> #data <script><!--</ #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--</" | <body> #data <script><!--</script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 20 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--</script" | <body> #data <script><!--</script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--" | <body> #data <script><!--<s #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 14 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<s" | <body> #data <script><!--<script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 19 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script" | <body> #data <script><!--<script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 20 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script " | <body> #data <script><!--<script < #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script <" | <body> #data <script><!--<script <a #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script <a" | <body> #data <script><!--<script </ #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </" | <body> #data <script><!--<script </s #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </s" | <body> #data <script><!--<script </script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 28 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </script" | <body> #data <script><!--<script </scripta #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </scripta" | <body> #data <script><!--<script </script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </script " | <body> #data <script><!--<script </script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </script>" | <body> #data <script><!--<script </script/ #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 29 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </script/" | <body> #data <script><!--<script </script < #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 30 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </script <" | <body> #data <script><!--<script </script <a #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </script <a" | <body> #data <script><!--<script </script </ #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </script </" | <body> #data <script><!--<script </script </script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </script </script" | <body> #data <script><!--<script </script </script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </script " | <body> #data <script><!--<script </script </script/ #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 38 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script </script " | <body> #data <script><!--<script </script </script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. #document | <html> | <head> | <script> | "<!--<script </script " | <body> #data <script><!--<script - #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 21 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script -" | <body> #data <script><!--<script -a #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script -a" | <body> #data <script><!--<script -- #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 22 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script --" | <body> #data <script><!--<script --a #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script --a" | <body> #data <script><!--<script --> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 23 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script -->" | <body> #data <script><!--<script -->< #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 24 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script --><" | <body> #data <script><!--<script --></ #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 25 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script --></" | <body> #data <script><!--<script --></script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 31 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script --></script" | <body> #data <script><!--<script --></script #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script -->" | <body> #data <script><!--<script --></script/ #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 32 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script -->" | <body> #data <script><!--<script --></script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. #document | <html> | <head> | <script> | "<!--<script -->" | <body> #data <script><!--<script><\/script>--></script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. #document | <html> | <head> | <script> | "<!--<script><\/script>-->" | <body> #data <script><!--<script></scr'+'ipt>--></script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. #document | <html> | <head> | <script> | "<!--<script></scr'+'ipt>-->" | <body> #data <script><!--<script></script><script></script></script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. #document | <html> | <head> | <script> | "<!--<script></script><script></script>" | <body> #data <script><!--<script></script><script></script>--><!--</script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. #document | <html> | <head> | <script> | "<!--<script></script><script></script>--><!--" | <body> #data <script><!--<script></script><script></script>-- ></script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. #document | <html> | <head> | <script> | "<!--<script></script><script></script>-- >" | <body> #data <script><!--<script></script><script></script>- -></script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. #document | <html> | <head> | <script> | "<!--<script></script><script></script>- ->" | <body> #data <script><!--<script></script><script></script>- - ></script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. #document | <html> | <head> | <script> | "<!--<script></script><script></script>- - >" | <body> #data <script><!--<script></script><script></script>-></script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. #document | <html> | <head> | <script> | "<!--<script></script><script></script>->" | <body> #data <script><!--<script>--!></script>X #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 34 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script>--!></script>X" | <body> #data <script><!--<scr'+'ipt></script>--></script> #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 44 Unexpected end tag (script). #document | <html> | <head> | <script> | "<!--<scr'+'ipt>" | <body> | "-->" #data <script><!--<script></scr'+'ipt></script>X #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 42 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "<!--<script></scr'+'ipt></script>X" | <body> #data <style><!--<style></style>--></style> #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. Line: 1 Col: 37 Unexpected end tag (style). #document | <html> | <head> | <style> | "<!--<style>" | <body> | "-->" #data <style><!--</style>X #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. #document | <html> | <head> | <style> | "<!--" | <body> | "X" #data <style><!--...</style>...--></style> #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. Line: 1 Col: 36 Unexpected end tag (style). #document | <html> | <head> | <style> | "<!--..." | <body> | "...-->" #data <style><!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style></style>X #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. #document | <html> | <head> | <style> | "<!--<br><html xmlns:v="urn:schemas-microsoft-com:vml"><!--[if !mso]><style>" | <body> | "X" #data <style><!--...<style><!--...--!></style>--></style> #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. Line: 1 Col: 51 Unexpected end tag (style). #document | <html> | <head> | <style> | "<!--...<style><!--...--!>" | <body> | "-->" #data <style><!--...</style><!-- --><style>@import ...</style> #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. #document | <html> | <head> | <style> | "<!--..." | <!-- --> | <style> | "@import ..." | <body> #data <style>...<style><!--...</style><!-- --></style> #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. Line: 1 Col: 48 Unexpected end tag (style). #document | <html> | <head> | <style> | "...<style><!--..." | <!-- --> | <body> #data <style>...<!--[if IE]><style>...</style>X #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. #document | <html> | <head> | <style> | "...<!--[if IE]><style>..." | <body> | "X" #data <title><!--<title>--> #errors Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. Line: 1 Col: 37 Unexpected end tag (title). #document | | | | "<!--<title>" | <body> | "-->" #data <title></title> #errors Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. #document | | | | "" | #data foo/title><link></head><body>X #errors Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE. Line: 1 Col: 37 Unexpected end of file. Expected end tag (title). #document | <html> | <head> | <title> | "foo/title><link></head><body>X" | <body> #data <noscript><!--<noscript></noscript>--></noscript> #errors Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. Line: 1 Col: 49 Unexpected end tag (noscript). #document | <html> | <head> | <noscript> | "<!--<noscript>" | <body> | "-->" #data <noscript><!--</noscript>X<noscript>--></noscript> #errors Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. #document | <html> | <head> | <noscript> | "<!--" | <body> | "X" | <noscript> | "-->" #data <noscript><iframe></noscript>X #errors Line: 1 Col: 10 Unexpected start tag (noscript). Expected DOCTYPE. #document | <html> | <head> | <noscript> | "<iframe>" | <body> | "X" #data <noframes><!--<noframes></noframes>--></noframes> #errors Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE. Line: 1 Col: 49 Unexpected end tag (noframes). #document | <html> | <head> | <noframes> | "<!--<noframes>" | <body> | "-->" #data <noframes><body><script><!--...</script></body></noframes></html> #errors Line: 1 Col: 10 Unexpected start tag (noframes). Expected DOCTYPE. #document | <html> | <head> | <noframes> | "<body><script><!--...</script></body>" | <body> #data <textarea><!--<textarea></textarea>--></textarea> #errors Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. Line: 1 Col: 49 Unexpected end tag (textarea). #document | <html> | <head> | <body> | <textarea> | "<!--<textarea>" | "-->" #data <textarea></textarea></textarea> #errors Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. #document | <html> | <head> | <body> | <textarea> | "</textarea>" #data <iframe><!--<iframe></iframe>--></iframe> #errors Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. Line: 1 Col: 41 Unexpected end tag (iframe). #document | <html> | <head> | <body> | <iframe> | "<!--<iframe>" | "-->" #data <iframe>...<!--X->...<!--/X->...</iframe> #errors Line: 1 Col: 8 Unexpected start tag (iframe). Expected DOCTYPE. #document | <html> | <head> | <body> | <iframe> | "...<!--X->...<!--/X->..." #data <xmp><!--<xmp></xmp>--></xmp> #errors Line: 1 Col: 5 Unexpected start tag (xmp). Expected DOCTYPE. Line: 1 Col: 29 Unexpected end tag (xmp). #document | <html> | <head> | <body> | <xmp> | "<!--<xmp>" | "-->" #data <noembed><!--<noembed></noembed>--></noembed> #errors Line: 1 Col: 9 Unexpected start tag (noembed). Expected DOCTYPE. Line: 1 Col: 45 Unexpected end tag (noembed). #document | <html> | <head> | <body> | <noembed> | "<!--<noembed>" | "-->" #data <!doctype html><table> #errors Line 2 Col 0 Unexpected end of file. Expected table content. #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | " " #data <!doctype html><table><td><span><font></span><span> #errors Line 1 Col 26 Unexpected table cell start tag (td) in the table body phase. Line 1 Col 45 Unexpected end tag (span). Line 1 Col 51 Expected closing tag. Unexpected end of file. #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <tbody> | <tr> | <td> | <span> | <font> | <font> | <span> #data <!doctype html><form><table></form><form></table></form> #errors 35: Stray end tag “formâ€. 41: Start tag “form†seen in “tableâ€. #document | <!DOCTYPE html> | <html> | <head> | <body> | <form> | <table> | <form> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/testdata/webkit/tests17.dat��������������������0000664�0000000�0000000�00000003721�12644643724�0026511�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#data <!doctype html><table><tbody><select><tr> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <table> | <tbody> | <tr> #data <!doctype html><table><tr><select><td> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <table> | <tbody> | <tr> | <td> #data <!doctype html><table><tr><td><select><td> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <tbody> | <tr> | <td> | <select> | <td> #data <!doctype html><table><tr><th><select><td> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <tbody> | <tr> | <th> | <select> | <td> #data <!doctype html><table><caption><select><tr> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <caption> | <select> | <tbody> | <tr> #data <!doctype html><select><tr> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> #data <!doctype html><select><td> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> #data <!doctype html><select><th> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> #data <!doctype html><select><tbody> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> #data <!doctype html><select><thead> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> #data <!doctype html><select><tfoot> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> #data <!doctype html><select><caption> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> #data <!doctype html><table><tr></table>a #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <tbody> | <tr> | "a" �����������������������������������������������golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/testdata/webkit/tests18.dat��������������������0000664�0000000�0000000�00000010056�12644643724�0026511�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#data <!doctype html><plaintext></plaintext> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <plaintext> | "</plaintext>" #data <!doctype html><table><plaintext></plaintext> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <plaintext> | "</plaintext>" | <table> #data <!doctype html><table><tbody><plaintext></plaintext> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <plaintext> | "</plaintext>" | <table> | <tbody> #data <!doctype html><table><tbody><tr><plaintext></plaintext> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <plaintext> | "</plaintext>" | <table> | <tbody> | <tr> #data <!doctype html><table><tbody><tr><plaintext></plaintext> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <plaintext> | "</plaintext>" | <table> | <tbody> | <tr> #data <!doctype html><table><td><plaintext></plaintext> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <tbody> | <tr> | <td> | <plaintext> | "</plaintext>" #data <!doctype html><table><caption><plaintext></plaintext> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <caption> | <plaintext> | "</plaintext>" #data <!doctype html><table><tr><style></script></style>abc #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | "abc" | <table> | <tbody> | <tr> | <style> | "</script>" #data <!doctype html><table><tr><script></style></script>abc #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | "abc" | <table> | <tbody> | <tr> | <script> | "</style>" #data <!doctype html><table><caption><style></script></style>abc #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <caption> | <style> | "</script>" | "abc" #data <!doctype html><table><td><style></script></style>abc #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <tbody> | <tr> | <td> | <style> | "</script>" | "abc" #data <!doctype html><select><script></style></script>abc #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <script> | "</style>" | "abc" #data <!doctype html><table><select><script></style></script>abc #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <script> | "</style>" | "abc" | <table> #data <!doctype html><table><tr><select><script></style></script>abc #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <script> | "</style>" | "abc" | <table> | <tbody> | <tr> #data <!doctype html><frameset></frameset><noframes>abc #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <noframes> | "abc" #data <!doctype html><frameset></frameset><noframes>abc</noframes><!--abc--> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <noframes> | "abc" | <!-- abc --> #data <!doctype html><frameset></frameset></html><noframes>abc #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <noframes> | "abc" #data <!doctype html><frameset></frameset></html><noframes>abc</noframes><!--abc--> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <noframes> | "abc" | <!-- abc --> #data <!doctype html><table><tr></tbody><tfoot> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <tbody> | <tr> | <tfoot> #data <!doctype html><table><td><svg></svg>abc<td> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <tbody> | <tr> | <td> | <svg svg> | "abc" | <td> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/testdata/webkit/tests19.dat��������������������0000664�0000000�0000000�00000042027�12644643724�0026515�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#data <!doctype html><math><mn DefinitionUrl="foo"> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <math math> | <math mn> | definitionURL="foo" #data <!doctype html><html></p><!--foo--> #errors #document | <!DOCTYPE html> | <html> | <!-- foo --> | <head> | <body> #data <!doctype html><head></head></p><!--foo--> #errors #document | <!DOCTYPE html> | <html> | <head> | <!-- foo --> | <body> #data <!doctype html><body><p><pre> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <pre> #data <!doctype html><body><p><listing> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <listing> #data <!doctype html><p><plaintext> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <plaintext> #data <!doctype html><p><h1> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <h1> #data <!doctype html><form><isindex> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <form> #data <!doctype html><isindex action="POST"> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <form> | action="POST" | <hr> | <label> | "This is a searchable index. Enter search keywords: " | <input> | name="isindex" | <hr> #data <!doctype html><isindex prompt="this is isindex"> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <form> | <hr> | <label> | "this is isindex" | <input> | name="isindex" | <hr> #data <!doctype html><isindex type="hidden"> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <form> | <hr> | <label> | "This is a searchable index. Enter search keywords: " | <input> | name="isindex" | type="hidden" | <hr> #data <!doctype html><isindex name="foo"> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <form> | <hr> | <label> | "This is a searchable index. Enter search keywords: " | <input> | name="isindex" | <hr> #data <!doctype html><ruby><p><rp> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <ruby> | <p> | <rp> #data <!doctype html><ruby><div><span><rp> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <ruby> | <div> | <span> | <rp> #data <!doctype html><ruby><div><p><rp> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <ruby> | <div> | <p> | <rp> #data <!doctype html><ruby><p><rt> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <ruby> | <p> | <rt> #data <!doctype html><ruby><div><span><rt> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <ruby> | <div> | <span> | <rt> #data <!doctype html><ruby><div><p><rt> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <ruby> | <div> | <p> | <rt> #data <!doctype html><math/><foo> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <math math> | <foo> #data <!doctype html><svg/><foo> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <svg svg> | <foo> #data <!doctype html><div></body><!--foo--> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <div> | <!-- foo --> #data <!doctype html><h1><div><h3><span></h1>foo #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <h1> | <div> | <h3> | <span> | "foo" #data <!doctype html><p></h3>foo #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | "foo" #data <!doctype html><h3><li>abc</h2>foo #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <h3> | <li> | "abc" | "foo" #data <!doctype html><table>abc<!--foo--> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | "abc" | <table> | <!-- foo --> #data <!doctype html><table> <!--foo--> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | " " | <!-- foo --> #data <!doctype html><table> b <!--foo--> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | " b " | <table> | <!-- foo --> #data <!doctype html><select><option><option> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <option> | <option> #data <!doctype html><select><option></optgroup> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <option> #data <!doctype html><select><option></optgroup> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <option> #data <!doctype html><p><math><mi><p><h1> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <math math> | <math mi> | <p> | <h1> #data <!doctype html><p><math><mo><p><h1> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <math math> | <math mo> | <p> | <h1> #data <!doctype html><p><math><mn><p><h1> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <math math> | <math mn> | <p> | <h1> #data <!doctype html><p><math><ms><p><h1> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <math math> | <math ms> | <p> | <h1> #data <!doctype html><p><math><mtext><p><h1> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <math math> | <math mtext> | <p> | <h1> #data <!doctype html><frameset></noframes> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> #data <!doctype html><html c=d><body></html><html a=b> #errors #document | <!DOCTYPE html> | <html> | a="b" | c="d" | <head> | <body> #data <!doctype html><html c=d><frameset></frameset></html><html a=b> #errors #document | <!DOCTYPE html> | <html> | a="b" | c="d" | <head> | <frameset> #data <!doctype html><html><frameset></frameset></html><!--foo--> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <!-- foo --> #data <!doctype html><html><frameset></frameset></html> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | " " #data <!doctype html><html><frameset></frameset></html>abc #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> #data <!doctype html><html><frameset></frameset></html><p> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> #data <!doctype html><html><frameset></frameset></html></p> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> #data <html><frameset></frameset></html><!doctype html> #errors #document | <html> | <head> | <frameset> #data <!doctype html><body><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> #data <!doctype html><p><frameset><frame> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <frame> #data <!doctype html><p>a<frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | "a" #data <!doctype html><p> <frameset><frame> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <frame> #data <!doctype html><pre><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <pre> #data <!doctype html><listing><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <listing> #data <!doctype html><li><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <li> #data <!doctype html><dd><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <dd> #data <!doctype html><dt><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <dt> #data <!doctype html><button><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <button> #data <!doctype html><applet><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <applet> #data <!doctype html><marquee><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <marquee> #data <!doctype html><object><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <object> #data <!doctype html><table><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> #data <!doctype html><area><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <area> #data <!doctype html><basefont><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <basefont> | <frameset> #data <!doctype html><bgsound><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <bgsound> | <frameset> #data <!doctype html><br><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <br> #data <!doctype html><embed><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <embed> #data <!doctype html><img><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <img> #data <!doctype html><input><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <input> #data <!doctype html><keygen><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <keygen> #data <!doctype html><wbr><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <wbr> #data <!doctype html><hr><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <hr> #data <!doctype html><textarea></textarea><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <textarea> #data <!doctype html><xmp></xmp><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <xmp> #data <!doctype html><iframe></iframe><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <iframe> #data <!doctype html><select></select><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> #data <!doctype html><svg></svg><frameset><frame> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <frame> #data <!doctype html><math></math><frameset><frame> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <frame> #data <!doctype html><svg><foreignObject><div> <frameset><frame> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <frame> #data <!doctype html><svg>a</svg><frameset><frame> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <svg svg> | "a" #data <!doctype html><svg> </svg><frameset><frame> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> | <frame> #data <html>aaa<frameset></frameset> #errors #document | <html> | <head> | <body> | "aaa" #data <html> a <frameset></frameset> #errors #document | <html> | <head> | <body> | "a " #data <!doctype html><div><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <frameset> #data <!doctype html><div><body><frameset> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <div> #data <!doctype html><p><math></p>a #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <math math> | "a" #data <!doctype html><p><math><mn><span></p>a #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <math math> | <math mn> | <span> | <p> | "a" #data <!doctype html><math></html> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <math math> #data <!doctype html><meta charset="ascii"> #errors #document | <!DOCTYPE html> | <html> | <head> | <meta> | charset="ascii" | <body> #data <!doctype html><meta http-equiv="content-type" content="text/html;charset=ascii"> #errors #document | <!DOCTYPE html> | <html> | <head> | <meta> | content="text/html;charset=ascii" | http-equiv="content-type" | <body> #data <!doctype html><head><!--aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--><meta charset="utf8"> #errors #document | <!DOCTYPE html> | <html> | <head> | <!-- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --> | <meta> | charset="utf8" | <body> #data <!doctype html><html a=b><head></head><html c=d> #errors #document | <!DOCTYPE html> | <html> | a="b" | c="d" | <head> | <body> #data <!doctype html><image/> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <img> #data <!doctype html>a<i>b<table>c<b>d</i>e</b>f #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | "a" | <i> | "bc" | <b> | "de" | "f" | <table> #data <!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <i> | "a" | <b> | "b" | <b> | <div> | <b> | <i> | "c" | <a> | "d" | <a> | "e" | <a> | "f" | <table> #data <!doctype html><i>a<b>b<div>c<a>d</i>e</b>f #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <i> | "a" | <b> | "b" | <b> | <div> | <b> | <i> | "c" | <a> | "d" | <a> | "e" | <a> | "f" #data <!doctype html><table><i>a<b>b<div>c</i> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <i> | "a" | <b> | "b" | <b> | <div> | <i> | "c" | <table> #data <!doctype html><table><i>a<b>b<div>c<a>d</i>e</b>f #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <i> | "a" | <b> | "b" | <b> | <div> | <b> | <i> | "c" | <a> | "d" | <a> | "e" | <a> | "f" | <table> #data <!doctype html><table><i>a<div>b<tr>c<b>d</i>e #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <i> | "a" | <div> | "b" | <i> | "c" | <b> | "d" | <b> | "e" | <table> | <tbody> | <tr> #data <!doctype html><table><td><table><i>a<div>b<b>c</i>d #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <tbody> | <tr> | <td> | <i> | "a" | <div> | <i> | "b" | <b> | "c" | <b> | "d" | <table> #data <!doctype html><body><bgsound> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <bgsound> #data <!doctype html><body><basefont> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <basefont> #data <!doctype html><a><b></a><basefont> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <a> | <b> | <basefont> #data <!doctype html><a><b></a><bgsound> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <a> | <b> | <bgsound> #data <!doctype html><figcaption><article></figcaption>a #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <figcaption> | <article> | "a" #data <!doctype html><summary><article></summary>a #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <summary> | <article> | "a" #data <!doctype html><p><a><plaintext>b #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <a> | <plaintext> | <a> | "b" #data <!DOCTYPE html><div>a<a></div>b<p>c</p>d #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <div> | "a" | <a> | <a> | "b" | <p> | "c" | "d" ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/html/testdata/webkit/tests2.dat���������������������0000664�0000000�0000000�00000032313�12644643724�0026422�0����������������������������������������������������������������������������������������������������ustar�00root����������������������������root����������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#data <!DOCTYPE html>Test #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | "Test" #data <textarea>test</div>test #errors Line: 1 Col: 10 Unexpected start tag (textarea). Expected DOCTYPE. Line: 1 Col: 24 Expected closing tag. Unexpected end of file. #document | <html> | <head> | <body> | <textarea> | "test</div>test" #data <table><td> #errors Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase. Line: 1 Col: 11 Expected closing tag. Unexpected end of file. #document | <html> | <head> | <body> | <table> | <tbody> | <tr> | <td> #data <table><td>test</tbody></table> #errors Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. Line: 1 Col: 11 Unexpected table cell start tag (td) in the table body phase. #document | <html> | <head> | <body> | <table> | <tbody> | <tr> | <td> | "test" #data <frame>test #errors Line: 1 Col: 7 Unexpected start tag (frame). Expected DOCTYPE. Line: 1 Col: 7 Unexpected start tag frame. Ignored. #document | <html> | <head> | <body> | "test" #data <!DOCTYPE html><frameset>test #errors Line: 1 Col: 29 Unepxected characters in the frameset phase. Characters ignored. Line: 1 Col: 29 Expected closing tag. Unexpected end of file. #document | <!DOCTYPE html> | <html> | <head> | <frameset> #data <!DOCTYPE html><frameset><!DOCTYPE html> #errors Line: 1 Col: 40 Unexpected DOCTYPE. Ignored. Line: 1 Col: 40 Expected closing tag. Unexpected end of file. #document | <!DOCTYPE html> | <html> | <head> | <frameset> #data <!DOCTYPE html><font><p><b>test</font> #errors Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. Line: 1 Col: 38 End tag (font) violates step 1, paragraph 3 of the adoption agency algorithm. #document | <!DOCTYPE html> | <html> | <head> | <body> | <font> | <p> | <font> | <b> | "test" #data <!DOCTYPE html><dt><div><dd> #errors Line: 1 Col: 28 Missing end tag (div, dt). #document | <!DOCTYPE html> | <html> | <head> | <body> | <dt> | <div> | <dd> #data <script></x #errors Line: 1 Col: 8 Unexpected start tag (script). Expected DOCTYPE. Line: 1 Col: 11 Unexpected end of file. Expected end tag (script). #document | <html> | <head> | <script> | "</x" | <body> #data <table><plaintext><td> #errors Line: 1 Col: 7 Unexpected start tag (table). Expected DOCTYPE. Line: 1 Col: 18 Unexpected start tag (plaintext) in table context caused voodoo mode. Line: 1 Col: 22 Unexpected end of file. Expected table content. #document | <html> | <head> | <body> | <plaintext> | "<td>" | <table> #data <plaintext></plaintext> #errors Line: 1 Col: 11 Unexpected start tag (plaintext). Expected DOCTYPE. Line: 1 Col: 23 Expected closing tag. Unexpected end of file. #document | <html> | <head> | <body> | <plaintext> | "</plaintext>" #data <!DOCTYPE html><table><tr>TEST #errors Line: 1 Col: 30 Unexpected non-space characters in table context caused voodoo mode. Line: 1 Col: 30 Unexpected end of file. Expected table content. #document | <!DOCTYPE html> | <html> | <head> | <body> | "TEST" | <table> | <tbody> | <tr> #data <!DOCTYPE html><body t1=1><body t2=2><body t3=3 t4=4> #errors Line: 1 Col: 37 Unexpected start tag (body). Line: 1 Col: 53 Unexpected start tag (body). #document | <!DOCTYPE html> | <html> | <head> | <body> | t1="1" | t2="2" | t3="3" | t4="4" #data </b test #errors Line: 1 Col: 8 Unexpected end of file in attribute name. Line: 1 Col: 8 End tag contains unexpected attributes. Line: 1 Col: 8 Unexpected end tag (b). Expected DOCTYPE. Line: 1 Col: 8 Unexpected end tag (b) after the (implied) root element. #document | <html> | <head> | <body> #data <!DOCTYPE html></b test<b &=&>X #errors Line: 1 Col: 32 Named entity didn't end with ';'. Line: 1 Col: 33 End tag contains unexpected attributes. Line: 1 Col: 33 Unexpected end tag (b) after the (implied) root element. #document | <!DOCTYPE html> | <html> | <head> | <body> | "X" #data <!doctypehtml><scrIPt type=text/x-foobar;baz>X</SCRipt #errors Line: 1 Col: 9 No space after literal string 'DOCTYPE'. Line: 1 Col: 54 Unexpected end of file in the tag name. #document | <!DOCTYPE html> | <html> | <head> | <script> | type="text/x-foobar;baz" | "X</SCRipt" | <body> #data & #errors Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. #document | <html> | <head> | <body> | "&" #data &# #errors Line: 1 Col: 1 Numeric entity expected. Got end of file instead. Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. #document | <html> | <head> | <body> | "&#" #data &#X #errors Line: 1 Col: 3 Numeric entity expected but none found. Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE. #document | <html> | <head> | <body> | "&#X" #data &#x #errors Line: 1 Col: 3 Numeric entity expected but none found. Line: 1 Col: 3 Unexpected non-space characters. Expected DOCTYPE. #document | <html> | <head> | <body> | "&#x" #data - #errors Line: 1 Col: 4 Numeric entity didn't end with ';'. Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. #document | <html> | <head> | <body> | "-" #data &x-test #errors Line: 1 Col: 1 Named entity expected. Got none. Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. #document | <html> | <head> | <body> | "&x-test" #data <!doctypehtml><p><li> #errors Line: 1 Col: 9 No space after literal string 'DOCTYPE'. #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <li> #data <!doctypehtml><p><dt> #errors Line: 1 Col: 9 No space after literal string 'DOCTYPE'. #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <dt> #data <!doctypehtml><p><dd> #errors Line: 1 Col: 9 No space after literal string 'DOCTYPE'. #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <dd> #data <!doctypehtml><p><form> #errors Line: 1 Col: 9 No space after literal string 'DOCTYPE'. Line: 1 Col: 23 Expected closing tag. Unexpected end of file. #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | <form> #data <!DOCTYPE html><p></P>X #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <p> | "X" #data & #errors Line: 1 Col: 4 Named entity didn't end with ';'. Line: 1 Col: 4 Unexpected non-space characters. Expected DOCTYPE. #document | <html> | <head> | <body> | "&" #data &AMp; #errors Line: 1 Col: 1 Named entity expected. Got none. Line: 1 Col: 1 Unexpected non-space characters. Expected DOCTYPE. #document | <html> | <head> | <body> | "&AMp;" #data <!DOCTYPE html><html><head></head><body><thisISasillyTESTelementNameToMakeSureCrazyTagNamesArePARSEDcorrectLY> #errors Line: 1 Col: 110 Expected closing tag. Unexpected end of file. #document | <!DOCTYPE html> | <html> | <head> | <body> | <thisisasillytestelementnametomakesurecrazytagnamesareparsedcorrectly> #data <!DOCTYPE html>X</body>X #errors Line: 1 Col: 24 Unexpected non-space characters in the after body phase. #document | <!DOCTYPE html> | <html> | <head> | <body> | "XX" #data <!DOCTYPE html><!-- X #errors Line: 1 Col: 21 Unexpected end of file in comment. #document | <!DOCTYPE html> | <!-- X --> | <html> | <head> | <body> #data <!DOCTYPE html><table><caption>test TEST</caption><td>test #errors Line: 1 Col: 54 Unexpected table cell start tag (td) in the table body phase. Line: 1 Col: 58 Expected closing tag. Unexpected end of file. #document | <!DOCTYPE html> | <html> | <head> | <body> | <table> | <caption> | "test TEST" | <tbody> | <tr> | <td> | "test" #data <!DOCTYPE html><select><option><optgroup> #errors Line: 1 Col: 41 Expected closing tag. Unexpected end of file. #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <option> | <optgroup> #data <!DOCTYPE html><select><optgroup><option></optgroup><option><select><option> #errors Line: 1 Col: 68 Unexpected select start tag in the select phase treated as select end tag. Line: 1 Col: 76 Expected closing tag. Unexpected end of file. #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <optgroup> | <option> | <option> | <option> #data <!DOCTYPE html><select><optgroup><option><optgroup> #errors Line: 1 Col: 51 Expected closing tag. Unexpected end of file. #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <optgroup> | <option> | <optgroup> #data <!DOCTYPE html><datalist><option>foo</datalist>bar #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <datalist> | <option> | "foo" | "bar" #data <!DOCTYPE html><font><input><input></font> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <font> | <input> | <input> #data <!DOCTYPE html><!-- XXX - XXX --> #errors #document | <!DOCTYPE html> | <!-- XXX - XXX --> | <html> | <head> | <body> #data <!DOCTYPE html><!-- XXX - XXX #errors Line: 1 Col: 29 Unexpected end of file in comment (-) #document | <!DOCTYPE html> | <!-- XXX - XXX --> | <html> | <head> | <body> #data <!DOCTYPE html><!-- XXX - XXX - XXX --> #errors #document | <!DOCTYPE html> | <!-- XXX - XXX - XXX --> | <html> | <head> | <body> #data <isindex test=x name=x> #errors Line: 1 Col: 23 Unexpected start tag (isindex). Expected DOCTYPE. Line: 1 Col: 23 Unexpected start tag isindex. Don't use it! #document | <html> | <head> | <body> | <form> | <hr> | <label> | "This is a searchable index. Enter search keywords: " | <input> | name="isindex" | test="x" | <hr> #data test test #errors Line: 2 Col: 4 Unexpected non-space characters. Expected DOCTYPE. #document | <html> | <head> | <body> | "test test" #data <!DOCTYPE html><body><title>test</body> #errors #document | | | | | | "test</body>" #data <!DOCTYPE html><body><title>X #errors #document | | | | | | "X" | <meta> | name="z" | <link> | rel="foo" | <style> | " x { content:"</style" } " #data <!DOCTYPE html><select><optgroup></optgroup></select> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> | <select> | <optgroup> #data #errors Line: 2 Col: 1 Unexpected End of file. Expected DOCTYPE. #document | <html> | <head> | <body> #data <!DOCTYPE html> <html> #errors #document | <!DOCTYPE html> | <html> | <head> | <body> #data <!DOCTYPE html><script> </script> <title>x #errors #document | | | | #errors Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. Line: 1 Col: 21 Unexpected start tag (script) that can be in head. Moved. #document | | | #errors Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. Line: 1 Col: 28 Unexpected start tag (style) that can be in head. Moved. #document | | | #errors Line: 1 Col: 6 Unexpected start tag (head). Expected DOCTYPE. #document | | | | | "x" | x #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. Line: 1 Col: 22 Unexpected end of file. Expected end tag (style). #document | | | --> x #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. #document | | | x #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. #document | | | x #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. #document | | | x #errors Line: 1 Col: 7 Unexpected start tag (style). Expected DOCTYPE. #document | | |

#errors #document | | | | | | ddd #errors #document | | | #errors #document | | | | |
  • | | ", "
    << Back to Go HTTP/2 demo server`) }) } func httpsHost() string { if *hostHTTPS != "" { return *hostHTTPS } if v := *httpsAddr; strings.HasPrefix(v, ":") { return "localhost" + v } else { return v } } func httpHost() string { if *hostHTTP != "" { return *hostHTTP } if v := *httpAddr; strings.HasPrefix(v, ":") { return "localhost" + v } else { return v } } func serveProdTLS() error { c, err := googlestorage.NewServiceClient() if err != nil { return err } slurp := func(key string) ([]byte, error) { const bucket = "http2-demo-server-tls" rc, _, err := c.GetObject(&googlestorage.Object{ Bucket: bucket, Key: key, }) if err != nil { return nil, fmt.Errorf("Error fetching GCS object %q in bucket %q: %v", key, bucket, err) } defer rc.Close() return ioutil.ReadAll(rc) } certPem, err := slurp("http2.golang.org.chained.pem") if err != nil { return err } keyPem, err := slurp("http2.golang.org.key") if err != nil { return err } cert, err := tls.X509KeyPair(certPem, keyPem) if err != nil { return err } srv := &http.Server{ TLSConfig: &tls.Config{ Certificates: []tls.Certificate{cert}, }, } http2.ConfigureServer(srv, &http2.Server{}) ln, err := net.Listen("tcp", ":443") if err != nil { return err } return srv.Serve(tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, srv.TLSConfig)) } type tcpKeepAliveListener struct { *net.TCPListener } func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) { tc, err := ln.AcceptTCP() if err != nil { return } tc.SetKeepAlive(true) tc.SetKeepAlivePeriod(3 * time.Minute) return tc, nil } func serveProd() error { errc := make(chan error, 2) go func() { errc <- http.ListenAndServe(":80", nil) }() go func() { errc <- serveProdTLS() }() return <-errc } func main() { var srv http.Server flag.BoolVar(&http2.VerboseLogs, "verbose", false, "Verbose HTTP/2 debugging.") flag.Parse() srv.Addr = *httpsAddr registerHandlers() if *prod { *hostHTTP = "http2.golang.org" *hostHTTPS = "http2.golang.org" log.Fatal(serveProd()) } url := "https://" + httpsHost() + "/" log.Printf("Listening on " + url) http2.ConfigureServer(&srv, &http2.Server{}) if *httpAddr != "" { go func() { log.Printf("Listening on http://" + httpHost() + "/ (for unencrypted HTTP/1)") log.Fatal(http.ListenAndServe(*httpAddr, nil)) }() } go func() { log.Fatal(srv.ListenAndServeTLS("server.crt", "server.key")) }() select {} } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/h2demo/launch.go000066400000000000000000000207771264464372400244750ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore package main import ( "bufio" "bytes" "encoding/json" "flag" "fmt" "io" "io/ioutil" "log" "net/http" "os" "strings" "time" "golang.org/x/oauth2" "golang.org/x/oauth2/google" compute "google.golang.org/api/compute/v1" ) var ( proj = flag.String("project", "symbolic-datum-552", "name of Project") zone = flag.String("zone", "us-central1-a", "GCE zone") mach = flag.String("machinetype", "n1-standard-1", "Machine type") instName = flag.String("instance_name", "http2-demo", "Name of VM instance.") sshPub = flag.String("ssh_public_key", "", "ssh public key file to authorize. Can modify later in Google's web UI anyway.") staticIP = flag.String("static_ip", "130.211.116.44", "Static IP to use. If empty, automatic.") writeObject = flag.String("write_object", "", "If non-empty, a VM isn't created and the flag value is Google Cloud Storage bucket/object to write. The contents from stdin.") publicObject = flag.Bool("write_object_is_public", false, "Whether the object created by --write_object should be public.") ) func readFile(v string) string { slurp, err := ioutil.ReadFile(v) if err != nil { log.Fatalf("Error reading %s: %v", v, err) } return strings.TrimSpace(string(slurp)) } var config = &oauth2.Config{ // The client-id and secret should be for an "Installed Application" when using // the CLI. Later we'll use a web application with a callback. ClientID: readFile("client-id.dat"), ClientSecret: readFile("client-secret.dat"), Endpoint: google.Endpoint, Scopes: []string{ compute.DevstorageFullControlScope, compute.ComputeScope, "https://www.googleapis.com/auth/sqlservice", "https://www.googleapis.com/auth/sqlservice.admin", }, RedirectURL: "urn:ietf:wg:oauth:2.0:oob", } const baseConfig = `#cloud-config coreos: units: - name: h2demo.service command: start content: | [Unit] Description=HTTP2 Demo [Service] ExecStartPre=/bin/bash -c 'mkdir -p /opt/bin && curl -s -o /opt/bin/h2demo http://storage.googleapis.com/http2-demo-server-tls/h2demo && chmod +x /opt/bin/h2demo' ExecStart=/opt/bin/h2demo --prod RestartSec=5s Restart=always Type=simple [Install] WantedBy=multi-user.target ` func main() { flag.Parse() if *proj == "" { log.Fatalf("Missing --project flag") } prefix := "https://www.googleapis.com/compute/v1/projects/" + *proj machType := prefix + "/zones/" + *zone + "/machineTypes/" + *mach const tokenFileName = "token.dat" tokenFile := tokenCacheFile(tokenFileName) tokenSource := oauth2.ReuseTokenSource(nil, tokenFile) token, err := tokenSource.Token() if err != nil { if *writeObject != "" { log.Fatalf("Can't use --write_object without a valid token.dat file already cached.") } log.Printf("Error getting token from %s: %v", tokenFileName, err) log.Printf("Get auth code from %v", config.AuthCodeURL("my-state")) fmt.Print("\nEnter auth code: ") sc := bufio.NewScanner(os.Stdin) sc.Scan() authCode := strings.TrimSpace(sc.Text()) token, err = config.Exchange(oauth2.NoContext, authCode) if err != nil { log.Fatalf("Error exchanging auth code for a token: %v", err) } if err := tokenFile.WriteToken(token); err != nil { log.Fatalf("Error writing to %s: %v", tokenFileName, err) } tokenSource = oauth2.ReuseTokenSource(token, nil) } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) if *writeObject != "" { writeCloudStorageObject(oauthClient) return } computeService, _ := compute.New(oauthClient) natIP := *staticIP if natIP == "" { // Try to find it by name. aggAddrList, err := computeService.Addresses.AggregatedList(*proj).Do() if err != nil { log.Fatal(err) } // http://godoc.org/code.google.com/p/google-api-go-client/compute/v1#AddressAggregatedList IPLoop: for _, asl := range aggAddrList.Items { for _, addr := range asl.Addresses { if addr.Name == *instName+"-ip" && addr.Status == "RESERVED" { natIP = addr.Address break IPLoop } } } } cloudConfig := baseConfig if *sshPub != "" { key := strings.TrimSpace(readFile(*sshPub)) cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", key) } if os.Getenv("USER") == "bradfitz" { cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n - %s\n", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwks9dwWKlRC+73gRbvYtVg0vdCwDSuIlyt4z6xa/YU/jTDynM4R4W10hm2tPjy8iR1k8XhDv4/qdxe6m07NjG/By1tkmGpm1mGwho4Pr5kbAAy/Qg+NLCSdAYnnE00FQEcFOC15GFVMOW2AzDGKisReohwH9eIzHPzdYQNPRWXE= bradfitz@papag.bradfitz.com") } const maxCloudConfig = 32 << 10 // per compute API docs if len(cloudConfig) > maxCloudConfig { log.Fatalf("cloud config length of %d bytes is over %d byte limit", len(cloudConfig), maxCloudConfig) } instance := &compute.Instance{ Name: *instName, Description: "Go Builder", MachineType: machType, Disks: []*compute.AttachedDisk{instanceDisk(computeService)}, Tags: &compute.Tags{ Items: []string{"http-server", "https-server"}, }, Metadata: &compute.Metadata{ Items: []*compute.MetadataItems{ { Key: "user-data", Value: &cloudConfig, }, }, }, NetworkInterfaces: []*compute.NetworkInterface{ &compute.NetworkInterface{ AccessConfigs: []*compute.AccessConfig{ &compute.AccessConfig{ Type: "ONE_TO_ONE_NAT", Name: "External NAT", NatIP: natIP, }, }, Network: prefix + "/global/networks/default", }, }, ServiceAccounts: []*compute.ServiceAccount{ { Email: "default", Scopes: []string{ compute.DevstorageFullControlScope, compute.ComputeScope, }, }, }, } log.Printf("Creating instance...") op, err := computeService.Instances.Insert(*proj, *zone, instance).Do() if err != nil { log.Fatalf("Failed to create instance: %v", err) } opName := op.Name log.Printf("Created. Waiting on operation %v", opName) OpLoop: for { time.Sleep(2 * time.Second) op, err := computeService.ZoneOperations.Get(*proj, *zone, opName).Do() if err != nil { log.Fatalf("Failed to get op %s: %v", opName, err) } switch op.Status { case "PENDING", "RUNNING": log.Printf("Waiting on operation %v", opName) continue case "DONE": if op.Error != nil { for _, operr := range op.Error.Errors { log.Printf("Error: %+v", operr) } log.Fatalf("Failed to start.") } log.Printf("Success. %+v", op) break OpLoop default: log.Fatalf("Unknown status %q: %+v", op.Status, op) } } inst, err := computeService.Instances.Get(*proj, *zone, *instName).Do() if err != nil { log.Fatalf("Error getting instance after creation: %v", err) } ij, _ := json.MarshalIndent(inst, "", " ") log.Printf("Instance: %s", ij) } func instanceDisk(svc *compute.Service) *compute.AttachedDisk { const imageURL = "https://www.googleapis.com/compute/v1/projects/coreos-cloud/global/images/coreos-stable-444-5-0-v20141016" diskName := *instName + "-disk" return &compute.AttachedDisk{ AutoDelete: true, Boot: true, Type: "PERSISTENT", InitializeParams: &compute.AttachedDiskInitializeParams{ DiskName: diskName, SourceImage: imageURL, DiskSizeGb: 50, }, } } func writeCloudStorageObject(httpClient *http.Client) { content := os.Stdin const maxSlurp = 1 << 20 var buf bytes.Buffer n, err := io.CopyN(&buf, content, maxSlurp) if err != nil && err != io.EOF { log.Fatalf("Error reading from stdin: %v, %v", n, err) } contentType := http.DetectContentType(buf.Bytes()) req, err := http.NewRequest("PUT", "https://storage.googleapis.com/"+*writeObject, io.MultiReader(&buf, content)) if err != nil { log.Fatal(err) } req.Header.Set("x-goog-api-version", "2") if *publicObject { req.Header.Set("x-goog-acl", "public-read") } req.Header.Set("Content-Type", contentType) res, err := httpClient.Do(req) if err != nil { log.Fatal(err) } if res.StatusCode != 200 { res.Write(os.Stderr) log.Fatalf("Failed.") } log.Printf("Success.") os.Exit(0) } type tokenCacheFile string func (f tokenCacheFile) Token() (*oauth2.Token, error) { slurp, err := ioutil.ReadFile(string(f)) if err != nil { return nil, err } t := new(oauth2.Token) if err := json.Unmarshal(slurp, t); err != nil { return nil, err } return t, nil } func (f tokenCacheFile) WriteToken(t *oauth2.Token) error { jt, err := json.Marshal(t) if err != nil { return err } return ioutil.WriteFile(string(f), jt, 0600) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/h2demo/rootCA.key000066400000000000000000000032131264464372400245570ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAt5fAjp4fTcekWUTfzsp0kyih1OYbsGL0KX1eRbSSR8Od0+9Q 62Hyny+GFwMTb4A/KU8mssoHvcceSAAbwfbxFK/+s51TobqUnORZrOoTZjkUygby XDSK99YBbcR1Pip8vwMTm4XKuLtCigeBBdjjAQdgUO28LENGlsMnmeYkJfODVGnV mr5Ltb9ANA8IKyTfsnHJ4iOCS/PlPbUj2q7YnoVLposUBMlgUb/CykX3mOoLb4yJ JQyA/iST6ZxiIEj36D4yWZ5lg7YJl+UiiBQHGCnPdGyipqV06ex0heYWcaiW8LWZ SUQ93jQ+WVCH8hT7DQO1dmsvUmXlq/JeAlwQ/QIDAQABAoIBAFFHV7JMAqPWnMYA nezY6J81v9+XN+7xABNWM2Q8uv4WdksbigGLTXR3/680Z2hXqJ7LMeC5XJACFT/e /Gr0vmpgOCygnCPfjGehGKpavtfksXV3edikUlnCXsOP1C//c1bFL+sMYmFCVgTx qYdDK8yKzXNGrKYT6q5YG7IglyRNV1rsQa8lM/5taFYiD1Ck/3tQi3YIq8Lcuser hrxsMABcQ6mi+EIvG6Xr4mfJug0dGJMHG4RG1UGFQn6RXrQq2+q53fC8ZbVUSi0j NQ918aKFzktwv+DouKU0ME4I9toks03gM860bAL7zCbKGmwR3hfgX/TqzVCWpG9E LDVfvekCgYEA8fk9N53jbBRmULUGEf4qWypcLGiZnNU0OeXWpbPV9aa3H0VDytA7 8fCN2dPAVDPqlthMDdVe983NCNwp2Yo8ZimDgowyIAKhdC25s1kejuaiH9OAPj3c 0f8KbriYX4n8zNHxFwK6Ae3pQ6EqOLJVCUsziUaZX9nyKY5aZlyX6xcCgYEAwjws K62PjC64U5wYddNLp+kNdJ4edx+a7qBb3mEgPvSFT2RO3/xafJyG8kQB30Mfstjd bRxyUV6N0vtX1zA7VQtRUAvfGCecpMo+VQZzcHXKzoRTnQ7eZg4Lmj5fQ9tOAKAo QCVBoSW/DI4PZL26CAMDcAba4Pa22ooLapoRIQsCgYA6pIfkkbxLNkpxpt2YwLtt Kr/590O7UaR9n6k8sW/aQBRDXNsILR1KDl2ifAIxpf9lnXgZJiwE7HiTfCAcW7c1 nzwDCI0hWuHcMTS/NYsFYPnLsstyyjVZI3FY0h4DkYKV9Q9z3zJLQ2hz/nwoD3gy b2pHC7giFcTts1VPV4Nt8wKBgHeFn4ihHJweg76vZz3Z78w7VNRWGFklUalVdDK7 gaQ7w2y/ROn/146mo0OhJaXFIFRlrpvdzVrU3GDf2YXJYDlM5ZRkObwbZADjksev WInzcgDy3KDg7WnPasRXbTfMU4t/AkW2p1QKbi3DnSVYuokDkbH2Beo45vxDxhKr C69RAoGBAIyo3+OJenoZmoNzNJl2WPW5MeBUzSh8T/bgyjFTdqFHF5WiYRD/lfHj x9Glyw2nutuT4hlOqHvKhgTYdDMsF2oQ72fe3v8Q5FU7FuKndNPEAyvKNXZaShVA hnlhv5DjXKb0wFWnt5PCCiQLtzG0yyHaITrrEme7FikkIcTxaX/Y -----END RSA PRIVATE KEY----- golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/h2demo/rootCA.pem000066400000000000000000000030421264464372400245500ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEWjCCA0KgAwIBAgIJALfRlWsI8YQHMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNV BAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEUMBIG A1UEChMLQnJhZGZpdHppbmMxEjAQBgNVBAMTCWxvY2FsaG9zdDEdMBsGCSqGSIb3 DQEJARYOYnJhZEBkYW5nYS5jb20wHhcNMTQwNzE1MjA0NjA1WhcNMTcwNTA0MjA0 NjA1WjB7MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBG cmFuY2lzY28xFDASBgNVBAoTC0JyYWRmaXR6aW5jMRIwEAYDVQQDEwlsb2NhbGhv c3QxHTAbBgkqhkiG9w0BCQEWDmJyYWRAZGFuZ2EuY29tMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAt5fAjp4fTcekWUTfzsp0kyih1OYbsGL0KX1eRbSS R8Od0+9Q62Hyny+GFwMTb4A/KU8mssoHvcceSAAbwfbxFK/+s51TobqUnORZrOoT ZjkUygbyXDSK99YBbcR1Pip8vwMTm4XKuLtCigeBBdjjAQdgUO28LENGlsMnmeYk JfODVGnVmr5Ltb9ANA8IKyTfsnHJ4iOCS/PlPbUj2q7YnoVLposUBMlgUb/CykX3 mOoLb4yJJQyA/iST6ZxiIEj36D4yWZ5lg7YJl+UiiBQHGCnPdGyipqV06ex0heYW caiW8LWZSUQ93jQ+WVCH8hT7DQO1dmsvUmXlq/JeAlwQ/QIDAQABo4HgMIHdMB0G A1UdDgQWBBRcAROthS4P4U7vTfjByC569R7E6DCBrQYDVR0jBIGlMIGigBRcAROt hS4P4U7vTfjByC569R7E6KF/pH0wezELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQKEwtCcmFkZml0emluYzES MBAGA1UEAxMJbG9jYWxob3N0MR0wGwYJKoZIhvcNAQkBFg5icmFkQGRhbmdhLmNv bYIJALfRlWsI8YQHMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAG6h U9f9sNH0/6oBbGGy2EVU0UgITUQIrFWo9rFkrW5k/XkDjQm+3lzjT0iGR4IxE/Ao eU6sQhua7wrWeFEn47GL98lnCsJdD7oZNhFmQ95Tb/LnDUjs5Yj9brP0NWzXfYU4 UK2ZnINJRcJpB8iRCaCxE8DdcUF0XqIEq6pA272snoLmiXLMvNl3kYEdm+je6voD 58SNVEUsztzQyXmJEhCpwVI0A6QCjzXj+qvpmw3ZZHi8JwXei8ZZBLTSFBki8Z7n sH9BBH38/SzUmAN4QHSPy1gjqm00OAE8NaYDkh/bzE4d7mLGGMWp/WE3KPSu82HF kPe6XoSbiLm/kxk32T0= -----END CERTIFICATE----- golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/h2demo/rootCA.srl000066400000000000000000000000211264464372400245610ustar00rootroot00000000000000E2CE26BF3285059C golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/h2demo/server.crt000066400000000000000000000022401264464372400246750ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDPjCCAiYCCQDizia/MoUFnDANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJV UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xFDASBgNVBAoT C0JyYWRmaXR6aW5jMRIwEAYDVQQDEwlsb2NhbGhvc3QxHTAbBgkqhkiG9w0BCQEW DmJyYWRAZGFuZ2EuY29tMB4XDTE0MDcxNTIwNTAyN1oXDTE1MTEyNzIwNTAyN1ow RzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQHEwJTRjEeMBwGA1UE ChMVYnJhZGZpdHogaHR0cDIgc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAs1Y9CyLFrdL8VQWN1WaifDqaZFnoqjHhCMlc1TfG2zA+InDifx2l gZD3o8FeNnAcfM2sPlk3+ZleOYw9P/CklFVDlvqmpCv9ss/BEp/dDaWvy1LmJ4c2 dbQJfmTxn7CV1H3TsVJvKdwFmdoABb41NoBp6+NNO7OtDyhbIMiCI0pL3Nefb3HL A7hIMo3DYbORTtJLTIH9W8YKrEWL0lwHLrYFx/UdutZnv+HjdmO6vCN4na55mjws /vjKQUmc7xeY7Xe20xDEG2oDKVkL2eD7FfyrYMS3rO1ExP2KSqlXYG/1S9I/fz88 F0GK7HX55b5WjZCl2J3ERVdnv/0MQv+sYQIDAQABMA0GCSqGSIb3DQEBBQUAA4IB AQC0zL+n/YpRZOdulSu9tS8FxrstXqGWoxfe+vIUgqfMZ5+0MkjJ/vW0FqlLDl2R rn4XaR3e7FmWkwdDVbq/UB6lPmoAaFkCgh9/5oapMaclNVNnfF3fjCJfRr+qj/iD EmJStTIN0ZuUjAlpiACmfnpEU55PafT5Zx+i1yE4FGjw8bJpFoyD4Hnm54nGjX19 KeCuvcYFUPnBm3lcL0FalF2AjqV02WTHYNQk7YF/oeO7NKBoEgvGvKG3x+xaOeBI dwvdq175ZsGul30h+QjrRlXhH/twcuaT3GSdoysDl9cCYE8f1Mk8PD6gan3uBCJU 90p6/CbU71bGbfpM2PHot2fm -----END CERTIFICATE----- golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/h2demo/server.key000066400000000000000000000032131264464372400246760ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAs1Y9CyLFrdL8VQWN1WaifDqaZFnoqjHhCMlc1TfG2zA+InDi fx2lgZD3o8FeNnAcfM2sPlk3+ZleOYw9P/CklFVDlvqmpCv9ss/BEp/dDaWvy1Lm J4c2dbQJfmTxn7CV1H3TsVJvKdwFmdoABb41NoBp6+NNO7OtDyhbIMiCI0pL3Nef b3HLA7hIMo3DYbORTtJLTIH9W8YKrEWL0lwHLrYFx/UdutZnv+HjdmO6vCN4na55 mjws/vjKQUmc7xeY7Xe20xDEG2oDKVkL2eD7FfyrYMS3rO1ExP2KSqlXYG/1S9I/ fz88F0GK7HX55b5WjZCl2J3ERVdnv/0MQv+sYQIDAQABAoIBADQ2spUwbY+bcz4p 3M66ECrNQTBggP40gYl2XyHxGGOu2xhZ94f9ELf1hjRWU2DUKWco1rJcdZClV6q3 qwmXvcM2Q/SMS8JW0ImkNVl/0/NqPxGatEnj8zY30d/L8hGFb0orzFu/XYA5gCP4 NbN2WrXgk3ZLeqwcNxHHtSiJWGJ/fPyeDWAu/apy75u9Xf2GlzBZmV6HYD9EfK80 LTlI60f5FO487CrJnboL7ovPJrIHn+k05xRQqwma4orpz932rTXnTjs9Lg6KtbQN a7PrqfAntIISgr11a66Mng3IYH1lYqJsWJJwX/xHT4WLEy0EH4/0+PfYemJekz2+ Co62drECgYEA6O9zVJZXrLSDsIi54cfxA7nEZWm5CAtkYWeAHa4EJ+IlZ7gIf9sL W8oFcEfFGpvwVqWZ+AsQ70dsjXAv3zXaG0tmg9FtqWp7pzRSMPidifZcQwWkKeTO gJnFmnVyed8h6GfjTEu4gxo1/S5U0V+mYSha01z5NTnN6ltKx1Or3b0CgYEAxRgm S30nZxnyg/V7ys61AZhst1DG2tkZXEMcA7dYhabMoXPJAP/EfhlWwpWYYUs/u0gS Wwmf5IivX5TlYScgmkvb/NYz0u4ZmOXkLTnLPtdKKFXhjXJcHjUP67jYmOxNlJLp V4vLRnFxTpffAV+OszzRxsXX6fvruwZBANYJeXUCgYBVouLFsFgfWGYp2rpr9XP4 KK25kvrBqF6JKOIDB1zjxNJ3pUMKrl8oqccCFoCyXa4oTM2kUX0yWxHfleUjrMq4 yimwQKiOZmV7fVLSSjSw6e/VfBd0h3gb82ygcplZkN0IclkwTY5SNKqwn/3y07V5 drqdhkrgdJXtmQ6O5YYECQKBgATERcDToQ1USlI4sKrB/wyv1AlG8dg/IebiVJ4e ZAyvcQmClFzq0qS+FiQUnB/WQw9TeeYrwGs1hxBHuJh16srwhLyDrbMvQP06qh8R 48F8UXXSRec22dV9MQphaROhu2qZdv1AC0WD3tqov6L33aqmEOi+xi8JgbT/PLk5 c/c1AoGBAI1A/02ryksW6/wc7/6SP2M2rTy4m1sD/GnrTc67EHnRcVBdKO6qH2RY nqC8YcveC2ZghgPTDsA3VGuzuBXpwY6wTyV99q6jxQJ6/xcrD9/NUG6Uwv/xfCxl IJLeBYEqQundSSny3VtaAUK8Ul1nxpTvVRNwtcyWTo8RHAAyNPWd -----END RSA PRIVATE KEY----- golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/h2i/000077500000000000000000000000001264464372400221635ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/h2i/README.md000066400000000000000000000046211264464372400234450ustar00rootroot00000000000000# h2i **h2i** is an interactive HTTP/2 ("h2") console debugger. Miss the good ol' days of telnetting to your HTTP/1.n servers? We're bringing you back. Features: - send raw HTTP/2 frames - PING - SETTINGS - HEADERS - etc - type in HTTP/1.n and have it auto-HPACK/frame-ify it for HTTP/2 - pretty print all received HTTP/2 frames from the peer (including HPACK decoding) - tab completion of commands, options Not yet features, but soon: - unnecessary CONTINUATION frames on short boundaries, to test peer implementations - request bodies (DATA frames) - send invalid frames for testing server implementations (supported by underlying Framer) Later: - act like a server ## Installation ``` $ go get golang.org/x/net/http2/h2i $ h2i ``` ## Demo ``` $ h2i Usage: h2i -insecure Whether to skip TLS cert validation -nextproto string Comma-separated list of NPN/ALPN protocol names to negotiate. (default "h2,h2-14") $ h2i google.com Connecting to google.com:443 ... Connected to 74.125.224.41:443 Negotiated protocol "h2-14" [FrameHeader SETTINGS len=18] [MAX_CONCURRENT_STREAMS = 100] [INITIAL_WINDOW_SIZE = 1048576] [MAX_FRAME_SIZE = 16384] [FrameHeader WINDOW_UPDATE len=4] Window-Increment = 983041 h2i> PING h2iSayHI [FrameHeader PING flags=ACK len=8] Data = "h2iSayHI" h2i> headers (as HTTP/1.1)> GET / HTTP/1.1 (as HTTP/1.1)> Host: ip.appspot.com (as HTTP/1.1)> User-Agent: h2i/brad-n-blake (as HTTP/1.1)> Opening Stream-ID 1: :authority = ip.appspot.com :method = GET :path = / :scheme = https user-agent = h2i/brad-n-blake [FrameHeader HEADERS flags=END_HEADERS stream=1 len=77] :status = "200" alternate-protocol = "443:quic,p=1" content-length = "15" content-type = "text/html" date = "Fri, 01 May 2015 23:06:56 GMT" server = "Google Frontend" [FrameHeader DATA flags=END_STREAM stream=1 len=15] "173.164.155.78\n" [FrameHeader PING len=8] Data = "\x00\x00\x00\x00\x00\x00\x00\x00" h2i> ping [FrameHeader PING flags=ACK len=8] Data = "h2i_ping" h2i> ping [FrameHeader PING flags=ACK len=8] Data = "h2i_ping" h2i> ping [FrameHeader GOAWAY len=22] Last-Stream-ID = 1; Error-Code = PROTOCOL_ERROR (1) ReadFrame: EOF ``` ## Status Quick few hour hack. So much yet to do. Feel free to file issues for bugs or wishlist items, but [@bmizerany](https://github.com/bmizerany/) and I aren't yet accepting pull requests until things settle down. golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/h2i/h2i.go000066400000000000000000000275711264464372400232100ustar00rootroot00000000000000// Copyright 2015 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. /* The h2i command is an interactive HTTP/2 console. Usage: $ h2i [flags] Interactive commands in the console: (all parts case-insensitive) ping [data] settings ack settings FOO=n BAR=z headers (open a new stream by typing HTTP/1.1) */ package main import ( "bufio" "bytes" "crypto/tls" "errors" "flag" "fmt" "io" "log" "net" "net/http" "os" "regexp" "strconv" "strings" "golang.org/x/crypto/ssh/terminal" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" ) // Flags var ( flagNextProto = flag.String("nextproto", "h2,h2-14", "Comma-separated list of NPN/ALPN protocol names to negotiate.") flagInsecure = flag.Bool("insecure", false, "Whether to skip TLS cert validation") flagSettings = flag.String("settings", "empty", "comma-separated list of KEY=value settings for the initial SETTINGS frame. The magic value 'empty' sends an empty initial settings frame, and the magic value 'omit' causes no initial settings frame to be sent.") ) type command struct { run func(*h2i, []string) error // required // complete optionally specifies tokens (case-insensitive) which are // valid for this subcommand. complete func() []string } var commands = map[string]command{ "ping": command{run: (*h2i).cmdPing}, "settings": command{ run: (*h2i).cmdSettings, complete: func() []string { return []string{ "ACK", http2.SettingHeaderTableSize.String(), http2.SettingEnablePush.String(), http2.SettingMaxConcurrentStreams.String(), http2.SettingInitialWindowSize.String(), http2.SettingMaxFrameSize.String(), http2.SettingMaxHeaderListSize.String(), } }, }, "quit": command{run: (*h2i).cmdQuit}, "headers": command{run: (*h2i).cmdHeaders}, } func usage() { fmt.Fprintf(os.Stderr, "Usage: h2i \n\n") flag.PrintDefaults() os.Exit(1) } // withPort adds ":443" if another port isn't already present. func withPort(host string) string { if _, _, err := net.SplitHostPort(host); err != nil { return net.JoinHostPort(host, "443") } return host } // h2i is the app's state. type h2i struct { host string tc *tls.Conn framer *http2.Framer term *terminal.Terminal // owned by the command loop: streamID uint32 hbuf bytes.Buffer henc *hpack.Encoder // owned by the readFrames loop: peerSetting map[http2.SettingID]uint32 hdec *hpack.Decoder } func main() { flag.Usage = usage flag.Parse() if flag.NArg() != 1 { usage() } log.SetFlags(0) host := flag.Arg(0) app := &h2i{ host: host, peerSetting: make(map[http2.SettingID]uint32), } app.henc = hpack.NewEncoder(&app.hbuf) if err := app.Main(); err != nil { if app.term != nil { app.logf("%v\n", err) } else { fmt.Fprintf(os.Stderr, "%v\n", err) } os.Exit(1) } fmt.Fprintf(os.Stdout, "\n") } func (app *h2i) Main() error { cfg := &tls.Config{ ServerName: app.host, NextProtos: strings.Split(*flagNextProto, ","), InsecureSkipVerify: *flagInsecure, } hostAndPort := withPort(app.host) log.Printf("Connecting to %s ...", hostAndPort) tc, err := tls.Dial("tcp", hostAndPort, cfg) if err != nil { return fmt.Errorf("Error dialing %s: %v", withPort(app.host), err) } log.Printf("Connected to %v", tc.RemoteAddr()) defer tc.Close() if err := tc.Handshake(); err != nil { return fmt.Errorf("TLS handshake: %v", err) } if !*flagInsecure { if err := tc.VerifyHostname(app.host); err != nil { return fmt.Errorf("VerifyHostname: %v", err) } } state := tc.ConnectionState() log.Printf("Negotiated protocol %q", state.NegotiatedProtocol) if !state.NegotiatedProtocolIsMutual || state.NegotiatedProtocol == "" { return fmt.Errorf("Could not negotiate protocol mutually") } if _, err := io.WriteString(tc, http2.ClientPreface); err != nil { return err } app.framer = http2.NewFramer(tc, tc) oldState, err := terminal.MakeRaw(0) if err != nil { return err } defer terminal.Restore(0, oldState) var screen = struct { io.Reader io.Writer }{os.Stdin, os.Stdout} app.term = terminal.NewTerminal(screen, "h2i> ") lastWord := regexp.MustCompile(`.+\W(\w+)$`) app.term.AutoCompleteCallback = func(line string, pos int, key rune) (newLine string, newPos int, ok bool) { if key != '\t' { return } if pos != len(line) { // TODO: we're being lazy for now, only supporting tab completion at the end. return } // Auto-complete for the command itself. if !strings.Contains(line, " ") { var name string name, _, ok = lookupCommand(line) if !ok { return } return name, len(name), true } _, c, ok := lookupCommand(line[:strings.IndexByte(line, ' ')]) if !ok || c.complete == nil { return } if strings.HasSuffix(line, " ") { app.logf("%s", strings.Join(c.complete(), " ")) return line, pos, true } m := lastWord.FindStringSubmatch(line) if m == nil { return line, len(line), true } soFar := m[1] var match []string for _, cand := range c.complete() { if len(soFar) > len(cand) || !strings.EqualFold(cand[:len(soFar)], soFar) { continue } match = append(match, cand) } if len(match) == 0 { return } if len(match) > 1 { // TODO: auto-complete any common prefix app.logf("%s", strings.Join(match, " ")) return line, pos, true } newLine = line[:len(line)-len(soFar)] + match[0] return newLine, len(newLine), true } errc := make(chan error, 2) go func() { errc <- app.readFrames() }() go func() { errc <- app.readConsole() }() return <-errc } func (app *h2i) logf(format string, args ...interface{}) { fmt.Fprintf(app.term, format+"\n", args...) } func (app *h2i) readConsole() error { if s := *flagSettings; s != "omit" { var args []string if s != "empty" { args = strings.Split(s, ",") } _, c, ok := lookupCommand("settings") if !ok { panic("settings command not found") } c.run(app, args) } for { line, err := app.term.ReadLine() if err == io.EOF { return nil } if err != nil { return fmt.Errorf("terminal.ReadLine: %v", err) } f := strings.Fields(line) if len(f) == 0 { continue } cmd, args := f[0], f[1:] if _, c, ok := lookupCommand(cmd); ok { err = c.run(app, args) } else { app.logf("Unknown command %q", line) } if err == errExitApp { return nil } if err != nil { return err } } } func lookupCommand(prefix string) (name string, c command, ok bool) { prefix = strings.ToLower(prefix) if c, ok = commands[prefix]; ok { return prefix, c, ok } for full, candidate := range commands { if strings.HasPrefix(full, prefix) { if c.run != nil { return "", command{}, false // ambiguous } c = candidate name = full } } return name, c, c.run != nil } var errExitApp = errors.New("internal sentinel error value to quit the console reading loop") func (a *h2i) cmdQuit(args []string) error { if len(args) > 0 { a.logf("the QUIT command takes no argument") return nil } return errExitApp } func (a *h2i) cmdSettings(args []string) error { if len(args) == 1 && strings.EqualFold(args[0], "ACK") { return a.framer.WriteSettingsAck() } var settings []http2.Setting for _, arg := range args { if strings.EqualFold(arg, "ACK") { a.logf("Error: ACK must be only argument with the SETTINGS command") return nil } eq := strings.Index(arg, "=") if eq == -1 { a.logf("Error: invalid argument %q (expected SETTING_NAME=nnnn)", arg) return nil } sid, ok := settingByName(arg[:eq]) if !ok { a.logf("Error: unknown setting name %q", arg[:eq]) return nil } val, err := strconv.ParseUint(arg[eq+1:], 10, 32) if err != nil { a.logf("Error: invalid argument %q (expected SETTING_NAME=nnnn)", arg) return nil } settings = append(settings, http2.Setting{ ID: sid, Val: uint32(val), }) } a.logf("Sending: %v", settings) return a.framer.WriteSettings(settings...) } func settingByName(name string) (http2.SettingID, bool) { for _, sid := range [...]http2.SettingID{ http2.SettingHeaderTableSize, http2.SettingEnablePush, http2.SettingMaxConcurrentStreams, http2.SettingInitialWindowSize, http2.SettingMaxFrameSize, http2.SettingMaxHeaderListSize, } { if strings.EqualFold(sid.String(), name) { return sid, true } } return 0, false } func (app *h2i) cmdPing(args []string) error { if len(args) > 1 { app.logf("invalid PING usage: only accepts 0 or 1 args") return nil // nil means don't end the program } var data [8]byte if len(args) == 1 { copy(data[:], args[0]) } else { copy(data[:], "h2i_ping") } return app.framer.WritePing(false, data) } func (app *h2i) cmdHeaders(args []string) error { if len(args) > 0 { app.logf("Error: HEADERS doesn't yet take arguments.") // TODO: flags for restricting window size, to force CONTINUATION // frames. return nil } var h1req bytes.Buffer app.term.SetPrompt("(as HTTP/1.1)> ") defer app.term.SetPrompt("h2i> ") for { line, err := app.term.ReadLine() if err != nil { return err } h1req.WriteString(line) h1req.WriteString("\r\n") if line == "" { break } } req, err := http.ReadRequest(bufio.NewReader(&h1req)) if err != nil { app.logf("Invalid HTTP/1.1 request: %v", err) return nil } if app.streamID == 0 { app.streamID = 1 } else { app.streamID += 2 } app.logf("Opening Stream-ID %d:", app.streamID) hbf := app.encodeHeaders(req) if len(hbf) > 16<<10 { app.logf("TODO: h2i doesn't yet write CONTINUATION frames. Copy it from transport.go") return nil } return app.framer.WriteHeaders(http2.HeadersFrameParam{ StreamID: app.streamID, BlockFragment: hbf, EndStream: req.Method == "GET" || req.Method == "HEAD", // good enough for now EndHeaders: true, // for now }) } func (app *h2i) readFrames() error { for { f, err := app.framer.ReadFrame() if err != nil { return fmt.Errorf("ReadFrame: %v", err) } app.logf("%v", f) switch f := f.(type) { case *http2.PingFrame: app.logf(" Data = %q", f.Data) case *http2.SettingsFrame: f.ForeachSetting(func(s http2.Setting) error { app.logf(" %v", s) app.peerSetting[s.ID] = s.Val return nil }) case *http2.WindowUpdateFrame: app.logf(" Window-Increment = %v\n", f.Increment) case *http2.GoAwayFrame: app.logf(" Last-Stream-ID = %d; Error-Code = %v (%d)\n", f.LastStreamID, f.ErrCode, f.ErrCode) case *http2.DataFrame: app.logf(" %q", f.Data()) case *http2.HeadersFrame: if f.HasPriority() { app.logf(" PRIORITY = %v", f.Priority) } if app.hdec == nil { // TODO: if the user uses h2i to send a SETTINGS frame advertising // something larger, we'll need to respect SETTINGS_HEADER_TABLE_SIZE // and stuff here instead of using the 4k default. But for now: tableSize := uint32(4 << 10) app.hdec = hpack.NewDecoder(tableSize, app.onNewHeaderField) } app.hdec.Write(f.HeaderBlockFragment()) } } } // called from readLoop func (app *h2i) onNewHeaderField(f hpack.HeaderField) { if f.Sensitive { app.logf(" %s = %q (SENSITIVE)", f.Name, f.Value) } app.logf(" %s = %q", f.Name, f.Value) } func (app *h2i) encodeHeaders(req *http.Request) []byte { app.hbuf.Reset() // TODO(bradfitz): figure out :authority-vs-Host stuff between http2 and Go host := req.Host if host == "" { host = req.URL.Host } path := req.URL.Path if path == "" { path = "/" } app.writeHeader(":authority", host) // probably not right for all sites app.writeHeader(":method", req.Method) app.writeHeader(":path", path) app.writeHeader(":scheme", "https") for k, vv := range req.Header { lowKey := strings.ToLower(k) if lowKey == "host" { continue } for _, v := range vv { app.writeHeader(lowKey, v) } } return app.hbuf.Bytes() } func (app *h2i) writeHeader(name, value string) { app.henc.WriteField(hpack.HeaderField{Name: name, Value: value}) app.logf(" %s = %s", name, value) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/headermap.go000066400000000000000000000026441264464372400237640ustar00rootroot00000000000000// Copyright 2014 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 http2 import ( "net/http" "strings" ) var ( commonLowerHeader = map[string]string{} // Go-Canonical-Case -> lower-case commonCanonHeader = map[string]string{} // lower-case -> Go-Canonical-Case ) func init() { for _, v := range []string{ "accept", "accept-charset", "accept-encoding", "accept-language", "accept-ranges", "age", "access-control-allow-origin", "allow", "authorization", "cache-control", "content-disposition", "content-encoding", "content-language", "content-length", "content-location", "content-range", "content-type", "cookie", "date", "etag", "expect", "expires", "from", "host", "if-match", "if-modified-since", "if-none-match", "if-unmodified-since", "last-modified", "link", "location", "max-forwards", "proxy-authenticate", "proxy-authorization", "range", "referer", "refresh", "retry-after", "server", "set-cookie", "strict-transport-security", "trailer", "transfer-encoding", "user-agent", "vary", "via", "www-authenticate", } { chk := http.CanonicalHeaderKey(v) commonLowerHeader[chk] = v commonCanonHeader[v] = chk } } func lowerHeader(v string) string { if s, ok := commonLowerHeader[v]; ok { return s } return strings.ToLower(v) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/hpack/000077500000000000000000000000001264464372400225675ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/hpack/encode.go000066400000000000000000000162001264464372400243520ustar00rootroot00000000000000// Copyright 2014 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 hpack import ( "io" ) const ( uint32Max = ^uint32(0) initialHeaderTableSize = 4096 ) type Encoder struct { dynTab dynamicTable // minSize is the minimum table size set by // SetMaxDynamicTableSize after the previous Header Table Size // Update. minSize uint32 // maxSizeLimit is the maximum table size this encoder // supports. This will protect the encoder from too large // size. maxSizeLimit uint32 // tableSizeUpdate indicates whether "Header Table Size // Update" is required. tableSizeUpdate bool w io.Writer buf []byte } // NewEncoder returns a new Encoder which performs HPACK encoding. An // encoded data is written to w. func NewEncoder(w io.Writer) *Encoder { e := &Encoder{ minSize: uint32Max, maxSizeLimit: initialHeaderTableSize, tableSizeUpdate: false, w: w, } e.dynTab.setMaxSize(initialHeaderTableSize) return e } // WriteField encodes f into a single Write to e's underlying Writer. // This function may also produce bytes for "Header Table Size Update" // if necessary. If produced, it is done before encoding f. func (e *Encoder) WriteField(f HeaderField) error { e.buf = e.buf[:0] if e.tableSizeUpdate { e.tableSizeUpdate = false if e.minSize < e.dynTab.maxSize { e.buf = appendTableSize(e.buf, e.minSize) } e.minSize = uint32Max e.buf = appendTableSize(e.buf, e.dynTab.maxSize) } idx, nameValueMatch := e.searchTable(f) if nameValueMatch { e.buf = appendIndexed(e.buf, idx) } else { indexing := e.shouldIndex(f) if indexing { e.dynTab.add(f) } if idx == 0 { e.buf = appendNewName(e.buf, f, indexing) } else { e.buf = appendIndexedName(e.buf, f, idx, indexing) } } n, err := e.w.Write(e.buf) if err == nil && n != len(e.buf) { err = io.ErrShortWrite } return err } // searchTable searches f in both stable and dynamic header tables. // The static header table is searched first. Only when there is no // exact match for both name and value, the dynamic header table is // then searched. If there is no match, i is 0. If both name and value // match, i is the matched index and nameValueMatch becomes true. If // only name matches, i points to that index and nameValueMatch // becomes false. func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool) { for idx, hf := range staticTable { if !constantTimeStringCompare(hf.Name, f.Name) { continue } if i == 0 { i = uint64(idx + 1) } if f.Sensitive { continue } if !constantTimeStringCompare(hf.Value, f.Value) { continue } i = uint64(idx + 1) nameValueMatch = true return } j, nameValueMatch := e.dynTab.search(f) if nameValueMatch || (i == 0 && j != 0) { i = j + uint64(len(staticTable)) } return } // SetMaxDynamicTableSize changes the dynamic header table size to v. // The actual size is bounded by the value passed to // SetMaxDynamicTableSizeLimit. func (e *Encoder) SetMaxDynamicTableSize(v uint32) { if v > e.maxSizeLimit { v = e.maxSizeLimit } if v < e.minSize { e.minSize = v } e.tableSizeUpdate = true e.dynTab.setMaxSize(v) } // SetMaxDynamicTableSizeLimit changes the maximum value that can be // specified in SetMaxDynamicTableSize to v. By default, it is set to // 4096, which is the same size of the default dynamic header table // size described in HPACK specification. If the current maximum // dynamic header table size is strictly greater than v, "Header Table // Size Update" will be done in the next WriteField call and the // maximum dynamic header table size is truncated to v. func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) { e.maxSizeLimit = v if e.dynTab.maxSize > v { e.tableSizeUpdate = true e.dynTab.setMaxSize(v) } } // shouldIndex reports whether f should be indexed. func (e *Encoder) shouldIndex(f HeaderField) bool { return !f.Sensitive && f.size() <= e.dynTab.maxSize } // appendIndexed appends index i, as encoded in "Indexed Header Field" // representation, to dst and returns the extended buffer. func appendIndexed(dst []byte, i uint64) []byte { first := len(dst) dst = appendVarInt(dst, 7, i) dst[first] |= 0x80 return dst } // appendNewName appends f, as encoded in one of "Literal Header field // - New Name" representation variants, to dst and returns the // extended buffer. // // If f.Sensitive is true, "Never Indexed" representation is used. If // f.Sensitive is false and indexing is true, "Inremental Indexing" // representation is used. func appendNewName(dst []byte, f HeaderField, indexing bool) []byte { dst = append(dst, encodeTypeByte(indexing, f.Sensitive)) dst = appendHpackString(dst, f.Name) return appendHpackString(dst, f.Value) } // appendIndexedName appends f and index i referring indexed name // entry, as encoded in one of "Literal Header field - Indexed Name" // representation variants, to dst and returns the extended buffer. // // If f.Sensitive is true, "Never Indexed" representation is used. If // f.Sensitive is false and indexing is true, "Incremental Indexing" // representation is used. func appendIndexedName(dst []byte, f HeaderField, i uint64, indexing bool) []byte { first := len(dst) var n byte if indexing { n = 6 } else { n = 4 } dst = appendVarInt(dst, n, i) dst[first] |= encodeTypeByte(indexing, f.Sensitive) return appendHpackString(dst, f.Value) } // appendTableSize appends v, as encoded in "Header Table Size Update" // representation, to dst and returns the extended buffer. func appendTableSize(dst []byte, v uint32) []byte { first := len(dst) dst = appendVarInt(dst, 5, uint64(v)) dst[first] |= 0x20 return dst } // appendVarInt appends i, as encoded in variable integer form using n // bit prefix, to dst and returns the extended buffer. // // See // http://http2.github.io/http2-spec/compression.html#integer.representation func appendVarInt(dst []byte, n byte, i uint64) []byte { k := uint64((1 << n) - 1) if i < k { return append(dst, byte(i)) } dst = append(dst, byte(k)) i -= k for ; i >= 128; i >>= 7 { dst = append(dst, byte(0x80|(i&0x7f))) } return append(dst, byte(i)) } // appendHpackString appends s, as encoded in "String Literal" // representation, to dst and returns the the extended buffer. // // s will be encoded in Huffman codes only when it produces strictly // shorter byte string. func appendHpackString(dst []byte, s string) []byte { huffmanLength := HuffmanEncodeLength(s) if huffmanLength < uint64(len(s)) { first := len(dst) dst = appendVarInt(dst, 7, huffmanLength) dst = AppendHuffmanString(dst, s) dst[first] |= 0x80 } else { dst = appendVarInt(dst, 7, uint64(len(s))) dst = append(dst, s...) } return dst } // encodeTypeByte returns type byte. If sensitive is true, type byte // for "Never Indexed" representation is returned. If sensitive is // false and indexing is true, type byte for "Incremental Indexing" // representation is returned. Otherwise, type byte for "Without // Indexing" is returned. func encodeTypeByte(indexing, sensitive bool) byte { if sensitive { return 0x10 } if indexing { return 0x40 } return 0 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/hpack/encode_test.go000066400000000000000000000205721264464372400254200ustar00rootroot00000000000000// Copyright 2014 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 hpack import ( "bytes" "encoding/hex" "reflect" "strings" "testing" ) func TestEncoderTableSizeUpdate(t *testing.T) { tests := []struct { size1, size2 uint32 wantHex string }{ // Should emit 2 table size updates (2048 and 4096) {2048, 4096, "3fe10f 3fe11f 82"}, // Should emit 1 table size update (2048) {16384, 2048, "3fe10f 82"}, } for _, tt := range tests { var buf bytes.Buffer e := NewEncoder(&buf) e.SetMaxDynamicTableSize(tt.size1) e.SetMaxDynamicTableSize(tt.size2) if err := e.WriteField(pair(":method", "GET")); err != nil { t.Fatal(err) } want := removeSpace(tt.wantHex) if got := hex.EncodeToString(buf.Bytes()); got != want { t.Errorf("e.SetDynamicTableSize %v, %v = %q; want %q", tt.size1, tt.size2, got, want) } } } func TestEncoderWriteField(t *testing.T) { var buf bytes.Buffer e := NewEncoder(&buf) var got []HeaderField d := NewDecoder(4<<10, func(f HeaderField) { got = append(got, f) }) tests := []struct { hdrs []HeaderField }{ {[]HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", "www.example.com"), }}, {[]HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", "www.example.com"), pair("cache-control", "no-cache"), }}, {[]HeaderField{ pair(":method", "GET"), pair(":scheme", "https"), pair(":path", "/index.html"), pair(":authority", "www.example.com"), pair("custom-key", "custom-value"), }}, } for i, tt := range tests { buf.Reset() got = got[:0] for _, hf := range tt.hdrs { if err := e.WriteField(hf); err != nil { t.Fatal(err) } } _, err := d.Write(buf.Bytes()) if err != nil { t.Errorf("%d. Decoder Write = %v", i, err) } if !reflect.DeepEqual(got, tt.hdrs) { t.Errorf("%d. Decoded %+v; want %+v", i, got, tt.hdrs) } } } func TestEncoderSearchTable(t *testing.T) { e := NewEncoder(nil) e.dynTab.add(pair("foo", "bar")) e.dynTab.add(pair("blake", "miz")) e.dynTab.add(pair(":method", "GET")) tests := []struct { hf HeaderField wantI uint64 wantMatch bool }{ // Name and Value match {pair("foo", "bar"), uint64(len(staticTable) + 3), true}, {pair("blake", "miz"), uint64(len(staticTable) + 2), true}, {pair(":method", "GET"), 2, true}, // Only name match because Sensitive == true {HeaderField{":method", "GET", true}, 2, false}, // Only Name matches {pair("foo", "..."), uint64(len(staticTable) + 3), false}, {pair("blake", "..."), uint64(len(staticTable) + 2), false}, {pair(":method", "..."), 2, false}, // None match {pair("foo-", "bar"), 0, false}, } for _, tt := range tests { if gotI, gotMatch := e.searchTable(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch { t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch) } } } func TestAppendVarInt(t *testing.T) { tests := []struct { n byte i uint64 want []byte }{ // Fits in a byte: {1, 0, []byte{0}}, {2, 2, []byte{2}}, {3, 6, []byte{6}}, {4, 14, []byte{14}}, {5, 30, []byte{30}}, {6, 62, []byte{62}}, {7, 126, []byte{126}}, {8, 254, []byte{254}}, // Multiple bytes: {5, 1337, []byte{31, 154, 10}}, } for _, tt := range tests { got := appendVarInt(nil, tt.n, tt.i) if !bytes.Equal(got, tt.want) { t.Errorf("appendVarInt(nil, %v, %v) = %v; want %v", tt.n, tt.i, got, tt.want) } } } func TestAppendHpackString(t *testing.T) { tests := []struct { s, wantHex string }{ // Huffman encoded {"www.example.com", "8c f1e3 c2e5 f23a 6ba0 ab90 f4ff"}, // Not Huffman encoded {"a", "01 61"}, // zero length {"", "00"}, } for _, tt := range tests { want := removeSpace(tt.wantHex) buf := appendHpackString(nil, tt.s) if got := hex.EncodeToString(buf); want != got { t.Errorf("appendHpackString(nil, %q) = %q; want %q", tt.s, got, want) } } } func TestAppendIndexed(t *testing.T) { tests := []struct { i uint64 wantHex string }{ // 1 byte {1, "81"}, {126, "fe"}, // 2 bytes {127, "ff00"}, {128, "ff01"}, } for _, tt := range tests { want := removeSpace(tt.wantHex) buf := appendIndexed(nil, tt.i) if got := hex.EncodeToString(buf); want != got { t.Errorf("appendIndex(nil, %v) = %q; want %q", tt.i, got, want) } } } func TestAppendNewName(t *testing.T) { tests := []struct { f HeaderField indexing bool wantHex string }{ // Incremental indexing {HeaderField{"custom-key", "custom-value", false}, true, "40 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"}, // Without indexing {HeaderField{"custom-key", "custom-value", false}, false, "00 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"}, // Never indexed {HeaderField{"custom-key", "custom-value", true}, true, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"}, {HeaderField{"custom-key", "custom-value", true}, false, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"}, } for _, tt := range tests { want := removeSpace(tt.wantHex) buf := appendNewName(nil, tt.f, tt.indexing) if got := hex.EncodeToString(buf); want != got { t.Errorf("appendNewName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want) } } } func TestAppendIndexedName(t *testing.T) { tests := []struct { f HeaderField i uint64 indexing bool wantHex string }{ // Incremental indexing {HeaderField{":status", "302", false}, 8, true, "48 82 6402"}, // Without indexing {HeaderField{":status", "302", false}, 8, false, "08 82 6402"}, // Never indexed {HeaderField{":status", "302", true}, 8, true, "18 82 6402"}, {HeaderField{":status", "302", true}, 8, false, "18 82 6402"}, } for _, tt := range tests { want := removeSpace(tt.wantHex) buf := appendIndexedName(nil, tt.f, tt.i, tt.indexing) if got := hex.EncodeToString(buf); want != got { t.Errorf("appendIndexedName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want) } } } func TestAppendTableSize(t *testing.T) { tests := []struct { i uint32 wantHex string }{ // Fits into 1 byte {30, "3e"}, // Extra byte {31, "3f00"}, {32, "3f01"}, } for _, tt := range tests { want := removeSpace(tt.wantHex) buf := appendTableSize(nil, tt.i) if got := hex.EncodeToString(buf); want != got { t.Errorf("appendTableSize(nil, %v) = %q; want %q", tt.i, got, want) } } } func TestEncoderSetMaxDynamicTableSize(t *testing.T) { var buf bytes.Buffer e := NewEncoder(&buf) tests := []struct { v uint32 wantUpdate bool wantMinSize uint32 wantMaxSize uint32 }{ // Set new table size to 2048 {2048, true, 2048, 2048}, // Set new table size to 16384, but still limited to // 4096 {16384, true, 2048, 4096}, } for _, tt := range tests { e.SetMaxDynamicTableSize(tt.v) if got := e.tableSizeUpdate; tt.wantUpdate != got { t.Errorf("e.tableSizeUpdate = %v; want %v", got, tt.wantUpdate) } if got := e.minSize; tt.wantMinSize != got { t.Errorf("e.minSize = %v; want %v", got, tt.wantMinSize) } if got := e.dynTab.maxSize; tt.wantMaxSize != got { t.Errorf("e.maxSize = %v; want %v", got, tt.wantMaxSize) } } } func TestEncoderSetMaxDynamicTableSizeLimit(t *testing.T) { e := NewEncoder(nil) // 4095 < initialHeaderTableSize means maxSize is truncated to // 4095. e.SetMaxDynamicTableSizeLimit(4095) if got, want := e.dynTab.maxSize, uint32(4095); got != want { t.Errorf("e.dynTab.maxSize = %v; want %v", got, want) } if got, want := e.maxSizeLimit, uint32(4095); got != want { t.Errorf("e.maxSizeLimit = %v; want %v", got, want) } if got, want := e.tableSizeUpdate, true; got != want { t.Errorf("e.tableSizeUpdate = %v; want %v", got, want) } // maxSize will be truncated to maxSizeLimit e.SetMaxDynamicTableSize(16384) if got, want := e.dynTab.maxSize, uint32(4095); got != want { t.Errorf("e.dynTab.maxSize = %v; want %v", got, want) } // 8192 > current maxSizeLimit, so maxSize does not change. e.SetMaxDynamicTableSizeLimit(8192) if got, want := e.dynTab.maxSize, uint32(4095); got != want { t.Errorf("e.dynTab.maxSize = %v; want %v", got, want) } if got, want := e.maxSizeLimit, uint32(8192); got != want { t.Errorf("e.maxSizeLimit = %v; want %v", got, want) } } func removeSpace(s string) string { return strings.Replace(s, " ", "", -1) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/hpack/hpack.go000066400000000000000000000351661264464372400242170ustar00rootroot00000000000000// Copyright 2014 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 hpack implements HPACK, a compression format for // efficiently representing HTTP header fields in the context of HTTP/2. // // See http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09 package hpack import ( "bytes" "errors" "fmt" ) // A DecodingError is something the spec defines as a decoding error. type DecodingError struct { Err error } func (de DecodingError) Error() string { return fmt.Sprintf("decoding error: %v", de.Err) } // An InvalidIndexError is returned when an encoder references a table // entry before the static table or after the end of the dynamic table. type InvalidIndexError int func (e InvalidIndexError) Error() string { return fmt.Sprintf("invalid indexed representation index %d", int(e)) } // A HeaderField is a name-value pair. Both the name and value are // treated as opaque sequences of octets. type HeaderField struct { Name, Value string // Sensitive means that this header field should never be // indexed. Sensitive bool } func (hf HeaderField) String() string { var suffix string if hf.Sensitive { suffix = " (sensitive)" } return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix) } func (hf *HeaderField) size() uint32 { // http://http2.github.io/http2-spec/compression.html#rfc.section.4.1 // "The size of the dynamic table is the sum of the size of // its entries. The size of an entry is the sum of its name's // length in octets (as defined in Section 5.2), its value's // length in octets (see Section 5.2), plus 32. The size of // an entry is calculated using the length of the name and // value without any Huffman encoding applied." // This can overflow if somebody makes a large HeaderField // Name and/or Value by hand, but we don't care, because that // won't happen on the wire because the encoding doesn't allow // it. return uint32(len(hf.Name) + len(hf.Value) + 32) } // A Decoder is the decoding context for incremental processing of // header blocks. type Decoder struct { dynTab dynamicTable emit func(f HeaderField) emitEnabled bool // whether calls to emit are enabled maxStrLen int // 0 means unlimited // buf is the unparsed buffer. It's only written to // saveBuf if it was truncated in the middle of a header // block. Because it's usually not owned, we can only // process it under Write. buf []byte // not owned; only valid during Write // saveBuf is previous data passed to Write which we weren't able // to fully parse before. Unlike buf, we own this data. saveBuf bytes.Buffer } // NewDecoder returns a new decoder with the provided maximum dynamic // table size. The emitFunc will be called for each valid field // parsed, in the same goroutine as calls to Write, before Write returns. func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder { d := &Decoder{ emit: emitFunc, emitEnabled: true, } d.dynTab.allowedMaxSize = maxDynamicTableSize d.dynTab.setMaxSize(maxDynamicTableSize) return d } // ErrStringLength is returned by Decoder.Write when the max string length // (as configured by Decoder.SetMaxStringLength) would be violated. var ErrStringLength = errors.New("hpack: string too long") // SetMaxStringLength sets the maximum size of a HeaderField name or // value string. If a string exceeds this length (even after any // decompression), Write will return ErrStringLength. // A value of 0 means unlimited and is the default from NewDecoder. func (d *Decoder) SetMaxStringLength(n int) { d.maxStrLen = n } // SetEmitFunc changes the callback used when new header fields // are decoded. // It must be non-nil. It does not affect EmitEnabled. func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField)) { d.emit = emitFunc } // SetEmitEnabled controls whether the emitFunc provided to NewDecoder // should be called. The default is true. // // This facility exists to let servers enforce MAX_HEADER_LIST_SIZE // while still decoding and keeping in-sync with decoder state, but // without doing unnecessary decompression or generating unnecessary // garbage for header fields past the limit. func (d *Decoder) SetEmitEnabled(v bool) { d.emitEnabled = v } // EmitEnabled reports whether calls to the emitFunc provided to NewDecoder // are currently enabled. The default is true. func (d *Decoder) EmitEnabled() bool { return d.emitEnabled } // TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their // underlying buffers for garbage reasons. func (d *Decoder) SetMaxDynamicTableSize(v uint32) { d.dynTab.setMaxSize(v) } // SetAllowedMaxDynamicTableSize sets the upper bound that the encoded // stream (via dynamic table size updates) may set the maximum size // to. func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) { d.dynTab.allowedMaxSize = v } type dynamicTable struct { // ents is the FIFO described at // http://http2.github.io/http2-spec/compression.html#rfc.section.2.3.2 // The newest (low index) is append at the end, and items are // evicted from the front. ents []HeaderField size uint32 maxSize uint32 // current maxSize allowedMaxSize uint32 // maxSize may go up to this, inclusive } func (dt *dynamicTable) setMaxSize(v uint32) { dt.maxSize = v dt.evict() } // TODO: change dynamicTable to be a struct with a slice and a size int field, // per http://http2.github.io/http2-spec/compression.html#rfc.section.4.1: // // // Then make add increment the size. maybe the max size should move from Decoder to // dynamicTable and add should return an ok bool if there was enough space. // // Later we'll need a remove operation on dynamicTable. func (dt *dynamicTable) add(f HeaderField) { dt.ents = append(dt.ents, f) dt.size += f.size() dt.evict() } // If we're too big, evict old stuff (front of the slice) func (dt *dynamicTable) evict() { base := dt.ents // keep base pointer of slice for dt.size > dt.maxSize { dt.size -= dt.ents[0].size() dt.ents = dt.ents[1:] } // Shift slice contents down if we evicted things. if len(dt.ents) != len(base) { copy(base, dt.ents) dt.ents = base[:len(dt.ents)] } } // constantTimeStringCompare compares string a and b in a constant // time manner. func constantTimeStringCompare(a, b string) bool { if len(a) != len(b) { return false } c := byte(0) for i := 0; i < len(a); i++ { c |= a[i] ^ b[i] } return c == 0 } // Search searches f in the table. The return value i is 0 if there is // no name match. If there is name match or name/value match, i is the // index of that entry (1-based). If both name and value match, // nameValueMatch becomes true. func (dt *dynamicTable) search(f HeaderField) (i uint64, nameValueMatch bool) { l := len(dt.ents) for j := l - 1; j >= 0; j-- { ent := dt.ents[j] if !constantTimeStringCompare(ent.Name, f.Name) { continue } if i == 0 { i = uint64(l - j) } if f.Sensitive { continue } if !constantTimeStringCompare(ent.Value, f.Value) { continue } i = uint64(l - j) nameValueMatch = true return } return } func (d *Decoder) maxTableIndex() int { return len(d.dynTab.ents) + len(staticTable) } func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) { if i < 1 { return } if i > uint64(d.maxTableIndex()) { return } if i <= uint64(len(staticTable)) { return staticTable[i-1], true } dents := d.dynTab.ents return dents[len(dents)-(int(i)-len(staticTable))], true } // Decode decodes an entire block. // // TODO: remove this method and make it incremental later? This is // easier for debugging now. func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) { var hf []HeaderField saveFunc := d.emit defer func() { d.emit = saveFunc }() d.emit = func(f HeaderField) { hf = append(hf, f) } if _, err := d.Write(p); err != nil { return nil, err } if err := d.Close(); err != nil { return nil, err } return hf, nil } func (d *Decoder) Close() error { if d.saveBuf.Len() > 0 { d.saveBuf.Reset() return DecodingError{errors.New("truncated headers")} } return nil } func (d *Decoder) Write(p []byte) (n int, err error) { if len(p) == 0 { // Prevent state machine CPU attacks (making us redo // work up to the point of finding out we don't have // enough data) return } // Only copy the data if we have to. Optimistically assume // that p will contain a complete header block. if d.saveBuf.Len() == 0 { d.buf = p } else { d.saveBuf.Write(p) d.buf = d.saveBuf.Bytes() d.saveBuf.Reset() } for len(d.buf) > 0 { err = d.parseHeaderFieldRepr() if err == errNeedMore { // Extra paranoia, making sure saveBuf won't // get too large. All the varint and string // reading code earlier should already catch // overlong things and return ErrStringLength, // but keep this as a last resort. const varIntOverhead = 8 // conservative if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) { return 0, ErrStringLength } d.saveBuf.Write(d.buf) return len(p), nil } if err != nil { break } } return len(p), err } // errNeedMore is an internal sentinel error value that means the // buffer is truncated and we need to read more data before we can // continue parsing. var errNeedMore = errors.New("need more data") type indexType int const ( indexedTrue indexType = iota indexedFalse indexedNever ) func (v indexType) indexed() bool { return v == indexedTrue } func (v indexType) sensitive() bool { return v == indexedNever } // returns errNeedMore if there isn't enough data available. // any other error is fatal. // consumes d.buf iff it returns nil. // precondition: must be called with len(d.buf) > 0 func (d *Decoder) parseHeaderFieldRepr() error { b := d.buf[0] switch { case b&128 != 0: // Indexed representation. // High bit set? // http://http2.github.io/http2-spec/compression.html#rfc.section.6.1 return d.parseFieldIndexed() case b&192 == 64: // 6.2.1 Literal Header Field with Incremental Indexing // 0b10xxxxxx: top two bits are 10 // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.1 return d.parseFieldLiteral(6, indexedTrue) case b&240 == 0: // 6.2.2 Literal Header Field without Indexing // 0b0000xxxx: top four bits are 0000 // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.2 return d.parseFieldLiteral(4, indexedFalse) case b&240 == 16: // 6.2.3 Literal Header Field never Indexed // 0b0001xxxx: top four bits are 0001 // http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.3 return d.parseFieldLiteral(4, indexedNever) case b&224 == 32: // 6.3 Dynamic Table Size Update // Top three bits are '001'. // http://http2.github.io/http2-spec/compression.html#rfc.section.6.3 return d.parseDynamicTableSizeUpdate() } return DecodingError{errors.New("invalid encoding")} } // (same invariants and behavior as parseHeaderFieldRepr) func (d *Decoder) parseFieldIndexed() error { buf := d.buf idx, buf, err := readVarInt(7, buf) if err != nil { return err } hf, ok := d.at(idx) if !ok { return DecodingError{InvalidIndexError(idx)} } d.buf = buf return d.callEmit(HeaderField{Name: hf.Name, Value: hf.Value}) } // (same invariants and behavior as parseHeaderFieldRepr) func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error { buf := d.buf nameIdx, buf, err := readVarInt(n, buf) if err != nil { return err } var hf HeaderField wantStr := d.emitEnabled || it.indexed() if nameIdx > 0 { ihf, ok := d.at(nameIdx) if !ok { return DecodingError{InvalidIndexError(nameIdx)} } hf.Name = ihf.Name } else { hf.Name, buf, err = d.readString(buf, wantStr) if err != nil { return err } } hf.Value, buf, err = d.readString(buf, wantStr) if err != nil { return err } d.buf = buf if it.indexed() { d.dynTab.add(hf) } hf.Sensitive = it.sensitive() return d.callEmit(hf) } func (d *Decoder) callEmit(hf HeaderField) error { if d.maxStrLen != 0 { if len(hf.Name) > d.maxStrLen || len(hf.Value) > d.maxStrLen { return ErrStringLength } } if d.emitEnabled { d.emit(hf) } return nil } // (same invariants and behavior as parseHeaderFieldRepr) func (d *Decoder) parseDynamicTableSizeUpdate() error { buf := d.buf size, buf, err := readVarInt(5, buf) if err != nil { return err } if size > uint64(d.dynTab.allowedMaxSize) { return DecodingError{errors.New("dynamic table size update too large")} } d.dynTab.setMaxSize(uint32(size)) d.buf = buf return nil } var errVarintOverflow = DecodingError{errors.New("varint integer overflow")} // readVarInt reads an unsigned variable length integer off the // beginning of p. n is the parameter as described in // http://http2.github.io/http2-spec/compression.html#rfc.section.5.1. // // n must always be between 1 and 8. // // The returned remain buffer is either a smaller suffix of p, or err != nil. // The error is errNeedMore if p doesn't contain a complete integer. func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) { if n < 1 || n > 8 { panic("bad n") } if len(p) == 0 { return 0, p, errNeedMore } i = uint64(p[0]) if n < 8 { i &= (1 << uint64(n)) - 1 } if i < (1< 0 { b := p[0] p = p[1:] i += uint64(b&127) << m if b&128 == 0 { return i, p, nil } m += 7 if m >= 63 { // TODO: proper overflow check. making this up. return 0, origP, errVarintOverflow } } return 0, origP, errNeedMore } // readString decodes an hpack string from p. // // wantStr is whether s will be used. If false, decompression and // []byte->string garbage are skipped if s will be ignored // anyway. This does mean that huffman decoding errors for non-indexed // strings past the MAX_HEADER_LIST_SIZE are ignored, but the server // is returning an error anyway, and because they're not indexed, the error // won't affect the decoding state. func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) { if len(p) == 0 { return "", p, errNeedMore } isHuff := p[0]&128 != 0 strLen, p, err := readVarInt(7, p) if err != nil { return "", p, err } if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) { return "", nil, ErrStringLength } if uint64(len(p)) < strLen { return "", p, errNeedMore } if !isHuff { if wantStr { s = string(p[:strLen]) } return s, p[strLen:], nil } if wantStr { buf := bufPool.Get().(*bytes.Buffer) buf.Reset() // don't trust others defer bufPool.Put(buf) if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil { buf.Reset() return "", nil, err } s = buf.String() buf.Reset() // be nice to GC } return s, p[strLen:], nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/hpack/hpack_test.go000066400000000000000000000624121264464372400252500ustar00rootroot00000000000000// Copyright 2014 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 hpack import ( "bufio" "bytes" "encoding/hex" "fmt" "math/rand" "reflect" "regexp" "strconv" "strings" "testing" "time" ) func TestStaticTable(t *testing.T) { fromSpec := ` +-------+-----------------------------+---------------+ | 1 | :authority | | | 2 | :method | GET | | 3 | :method | POST | | 4 | :path | / | | 5 | :path | /index.html | | 6 | :scheme | http | | 7 | :scheme | https | | 8 | :status | 200 | | 9 | :status | 204 | | 10 | :status | 206 | | 11 | :status | 304 | | 12 | :status | 400 | | 13 | :status | 404 | | 14 | :status | 500 | | 15 | accept-charset | | | 16 | accept-encoding | gzip, deflate | | 17 | accept-language | | | 18 | accept-ranges | | | 19 | accept | | | 20 | access-control-allow-origin | | | 21 | age | | | 22 | allow | | | 23 | authorization | | | 24 | cache-control | | | 25 | content-disposition | | | 26 | content-encoding | | | 27 | content-language | | | 28 | content-length | | | 29 | content-location | | | 30 | content-range | | | 31 | content-type | | | 32 | cookie | | | 33 | date | | | 34 | etag | | | 35 | expect | | | 36 | expires | | | 37 | from | | | 38 | host | | | 39 | if-match | | | 40 | if-modified-since | | | 41 | if-none-match | | | 42 | if-range | | | 43 | if-unmodified-since | | | 44 | last-modified | | | 45 | link | | | 46 | location | | | 47 | max-forwards | | | 48 | proxy-authenticate | | | 49 | proxy-authorization | | | 50 | range | | | 51 | referer | | | 52 | refresh | | | 53 | retry-after | | | 54 | server | | | 55 | set-cookie | | | 56 | strict-transport-security | | | 57 | transfer-encoding | | | 58 | user-agent | | | 59 | vary | | | 60 | via | | | 61 | www-authenticate | | +-------+-----------------------------+---------------+ ` bs := bufio.NewScanner(strings.NewReader(fromSpec)) re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`) for bs.Scan() { l := bs.Text() if !strings.Contains(l, "|") { continue } m := re.FindStringSubmatch(l) if m == nil { continue } i, err := strconv.Atoi(m[1]) if err != nil { t.Errorf("Bogus integer on line %q", l) continue } if i < 1 || i > len(staticTable) { t.Errorf("Bogus index %d on line %q", i, l) continue } if got, want := staticTable[i-1].Name, m[2]; got != want { t.Errorf("header index %d name = %q; want %q", i, got, want) } if got, want := staticTable[i-1].Value, m[3]; got != want { t.Errorf("header index %d value = %q; want %q", i, got, want) } } if err := bs.Err(); err != nil { t.Error(err) } } func (d *Decoder) mustAt(idx int) HeaderField { if hf, ok := d.at(uint64(idx)); !ok { panic(fmt.Sprintf("bogus index %d", idx)) } else { return hf } } func TestDynamicTableAt(t *testing.T) { d := NewDecoder(4096, nil) at := d.mustAt if got, want := at(2), (pair(":method", "GET")); got != want { t.Errorf("at(2) = %v; want %v", got, want) } d.dynTab.add(pair("foo", "bar")) d.dynTab.add(pair("blake", "miz")) if got, want := at(len(staticTable)+1), (pair("blake", "miz")); got != want { t.Errorf("at(dyn 1) = %v; want %v", got, want) } if got, want := at(len(staticTable)+2), (pair("foo", "bar")); got != want { t.Errorf("at(dyn 2) = %v; want %v", got, want) } if got, want := at(3), (pair(":method", "POST")); got != want { t.Errorf("at(3) = %v; want %v", got, want) } } func TestDynamicTableSearch(t *testing.T) { dt := dynamicTable{} dt.setMaxSize(4096) dt.add(pair("foo", "bar")) dt.add(pair("blake", "miz")) dt.add(pair(":method", "GET")) tests := []struct { hf HeaderField wantI uint64 wantMatch bool }{ // Name and Value match {pair("foo", "bar"), 3, true}, {pair(":method", "GET"), 1, true}, // Only name match because of Sensitive == true {HeaderField{"blake", "miz", true}, 2, false}, // Only Name matches {pair("foo", "..."), 3, false}, {pair("blake", "..."), 2, false}, {pair(":method", "..."), 1, false}, // None match {pair("foo-", "bar"), 0, false}, } for _, tt := range tests { if gotI, gotMatch := dt.search(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch { t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch) } } } func TestDynamicTableSizeEvict(t *testing.T) { d := NewDecoder(4096, nil) if want := uint32(0); d.dynTab.size != want { t.Fatalf("size = %d; want %d", d.dynTab.size, want) } add := d.dynTab.add add(pair("blake", "eats pizza")) if want := uint32(15 + 32); d.dynTab.size != want { t.Fatalf("after pizza, size = %d; want %d", d.dynTab.size, want) } add(pair("foo", "bar")) if want := uint32(15 + 32 + 6 + 32); d.dynTab.size != want { t.Fatalf("after foo bar, size = %d; want %d", d.dynTab.size, want) } d.dynTab.setMaxSize(15 + 32 + 1 /* slop */) if want := uint32(6 + 32); d.dynTab.size != want { t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want) } if got, want := d.mustAt(len(staticTable)+1), (pair("foo", "bar")); got != want { t.Errorf("at(dyn 1) = %v; want %v", got, want) } add(pair("long", strings.Repeat("x", 500))) if want := uint32(0); d.dynTab.size != want { t.Fatalf("after big one, size = %d; want %d", d.dynTab.size, want) } } func TestDecoderDecode(t *testing.T) { tests := []struct { name string in []byte want []HeaderField wantDynTab []HeaderField // newest entry first }{ // C.2.1 Literal Header Field with Indexing // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.1 {"C.2.1", dehex("400a 6375 7374 6f6d 2d6b 6579 0d63 7573 746f 6d2d 6865 6164 6572"), []HeaderField{pair("custom-key", "custom-header")}, []HeaderField{pair("custom-key", "custom-header")}, }, // C.2.2 Literal Header Field without Indexing // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.2 {"C.2.2", dehex("040c 2f73 616d 706c 652f 7061 7468"), []HeaderField{pair(":path", "/sample/path")}, []HeaderField{}}, // C.2.3 Literal Header Field never Indexed // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.3 {"C.2.3", dehex("1008 7061 7373 776f 7264 0673 6563 7265 74"), []HeaderField{{"password", "secret", true}}, []HeaderField{}}, // C.2.4 Indexed Header Field // http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.4 {"C.2.4", []byte("\x82"), []HeaderField{pair(":method", "GET")}, []HeaderField{}}, } for _, tt := range tests { d := NewDecoder(4096, nil) hf, err := d.DecodeFull(tt.in) if err != nil { t.Errorf("%s: %v", tt.name, err) continue } if !reflect.DeepEqual(hf, tt.want) { t.Errorf("%s: Got %v; want %v", tt.name, hf, tt.want) } gotDynTab := d.dynTab.reverseCopy() if !reflect.DeepEqual(gotDynTab, tt.wantDynTab) { t.Errorf("%s: dynamic table after = %v; want %v", tt.name, gotDynTab, tt.wantDynTab) } } } func (dt *dynamicTable) reverseCopy() (hf []HeaderField) { hf = make([]HeaderField, len(dt.ents)) for i := range hf { hf[i] = dt.ents[len(dt.ents)-1-i] } return } type encAndWant struct { enc []byte want []HeaderField wantDynTab []HeaderField wantDynSize uint32 } // C.3 Request Examples without Huffman Coding // http://http2.github.io/http2-spec/compression.html#rfc.section.C.3 func TestDecodeC3_NoHuffman(t *testing.T) { testDecodeSeries(t, 4096, []encAndWant{ {dehex("8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d"), []HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", "www.example.com"), }, []HeaderField{ pair(":authority", "www.example.com"), }, 57, }, {dehex("8286 84be 5808 6e6f 2d63 6163 6865"), []HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", "www.example.com"), pair("cache-control", "no-cache"), }, []HeaderField{ pair("cache-control", "no-cache"), pair(":authority", "www.example.com"), }, 110, }, {dehex("8287 85bf 400a 6375 7374 6f6d 2d6b 6579 0c63 7573 746f 6d2d 7661 6c75 65"), []HeaderField{ pair(":method", "GET"), pair(":scheme", "https"), pair(":path", "/index.html"), pair(":authority", "www.example.com"), pair("custom-key", "custom-value"), }, []HeaderField{ pair("custom-key", "custom-value"), pair("cache-control", "no-cache"), pair(":authority", "www.example.com"), }, 164, }, }) } // C.4 Request Examples with Huffman Coding // http://http2.github.io/http2-spec/compression.html#rfc.section.C.4 func TestDecodeC4_Huffman(t *testing.T) { testDecodeSeries(t, 4096, []encAndWant{ {dehex("8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff"), []HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", "www.example.com"), }, []HeaderField{ pair(":authority", "www.example.com"), }, 57, }, {dehex("8286 84be 5886 a8eb 1064 9cbf"), []HeaderField{ pair(":method", "GET"), pair(":scheme", "http"), pair(":path", "/"), pair(":authority", "www.example.com"), pair("cache-control", "no-cache"), }, []HeaderField{ pair("cache-control", "no-cache"), pair(":authority", "www.example.com"), }, 110, }, {dehex("8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 a849 e95b b8e8 b4bf"), []HeaderField{ pair(":method", "GET"), pair(":scheme", "https"), pair(":path", "/index.html"), pair(":authority", "www.example.com"), pair("custom-key", "custom-value"), }, []HeaderField{ pair("custom-key", "custom-value"), pair("cache-control", "no-cache"), pair(":authority", "www.example.com"), }, 164, }, }) } // http://http2.github.io/http2-spec/compression.html#rfc.section.C.5 // "This section shows several consecutive header lists, corresponding // to HTTP responses, on the same connection. The HTTP/2 setting // parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256 // octets, causing some evictions to occur." func TestDecodeC5_ResponsesNoHuff(t *testing.T) { testDecodeSeries(t, 256, []encAndWant{ {dehex(` 4803 3330 3258 0770 7269 7661 7465 611d 4d6f 6e2c 2032 3120 4f63 7420 3230 3133 2032 303a 3133 3a32 3120 474d 546e 1768 7474 7073 3a2f 2f77 7777 2e65 7861 6d70 6c65 2e63 6f6d `), []HeaderField{ pair(":status", "302"), pair("cache-control", "private"), pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), pair("location", "https://www.example.com"), }, []HeaderField{ pair("location", "https://www.example.com"), pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), pair("cache-control", "private"), pair(":status", "302"), }, 222, }, {dehex("4803 3330 37c1 c0bf"), []HeaderField{ pair(":status", "307"), pair("cache-control", "private"), pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), pair("location", "https://www.example.com"), }, []HeaderField{ pair(":status", "307"), pair("location", "https://www.example.com"), pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), pair("cache-control", "private"), }, 222, }, {dehex(` 88c1 611d 4d6f 6e2c 2032 3120 4f63 7420 3230 3133 2032 303a 3133 3a32 3220 474d 54c0 5a04 677a 6970 7738 666f 6f3d 4153 444a 4b48 514b 425a 584f 5157 454f 5049 5541 5851 5745 4f49 553b 206d 6178 2d61 6765 3d33 3630 303b 2076 6572 7369 6f6e 3d31 `), []HeaderField{ pair(":status", "200"), pair("cache-control", "private"), pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"), pair("location", "https://www.example.com"), pair("content-encoding", "gzip"), pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"), }, []HeaderField{ pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"), pair("content-encoding", "gzip"), pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"), }, 215, }, }) } // http://http2.github.io/http2-spec/compression.html#rfc.section.C.6 // "This section shows the same examples as the previous section, but // using Huffman encoding for the literal values. The HTTP/2 setting // parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256 // octets, causing some evictions to occur. The eviction mechanism // uses the length of the decoded literal values, so the same // evictions occurs as in the previous section." func TestDecodeC6_ResponsesHuffman(t *testing.T) { testDecodeSeries(t, 256, []encAndWant{ {dehex(` 4882 6402 5885 aec3 771a 4b61 96d0 7abe 9410 54d4 44a8 2005 9504 0b81 66e0 82a6 2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8 e9ae 82ae 43d3 `), []HeaderField{ pair(":status", "302"), pair("cache-control", "private"), pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), pair("location", "https://www.example.com"), }, []HeaderField{ pair("location", "https://www.example.com"), pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), pair("cache-control", "private"), pair(":status", "302"), }, 222, }, {dehex("4883 640e ffc1 c0bf"), []HeaderField{ pair(":status", "307"), pair("cache-control", "private"), pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), pair("location", "https://www.example.com"), }, []HeaderField{ pair(":status", "307"), pair("location", "https://www.example.com"), pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), pair("cache-control", "private"), }, 222, }, {dehex(` 88c1 6196 d07a be94 1054 d444 a820 0595 040b 8166 e084 a62d 1bff c05a 839b d9ab 77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07 `), []HeaderField{ pair(":status", "200"), pair("cache-control", "private"), pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"), pair("location", "https://www.example.com"), pair("content-encoding", "gzip"), pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"), }, []HeaderField{ pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"), pair("content-encoding", "gzip"), pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"), }, 215, }, }) } func testDecodeSeries(t *testing.T, size uint32, steps []encAndWant) { d := NewDecoder(size, nil) for i, step := range steps { hf, err := d.DecodeFull(step.enc) if err != nil { t.Fatalf("Error at step index %d: %v", i, err) } if !reflect.DeepEqual(hf, step.want) { t.Fatalf("At step index %d: Got headers %v; want %v", i, hf, step.want) } gotDynTab := d.dynTab.reverseCopy() if !reflect.DeepEqual(gotDynTab, step.wantDynTab) { t.Errorf("After step index %d, dynamic table = %v; want %v", i, gotDynTab, step.wantDynTab) } if d.dynTab.size != step.wantDynSize { t.Errorf("After step index %d, dynamic table size = %v; want %v", i, d.dynTab.size, step.wantDynSize) } } } func TestHuffmanDecode(t *testing.T) { tests := []struct { inHex, want string }{ {"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"}, {"a8eb 1064 9cbf", "no-cache"}, {"25a8 49e9 5ba9 7d7f", "custom-key"}, {"25a8 49e9 5bb8 e8b4 bf", "custom-value"}, {"6402", "302"}, {"aec3 771a 4b", "private"}, {"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"}, {"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"}, {"9bd9 ab", "gzip"}, {"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"}, } for i, tt := range tests { var buf bytes.Buffer in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1)) if err != nil { t.Errorf("%d. hex input error: %v", i, err) continue } if _, err := HuffmanDecode(&buf, in); err != nil { t.Errorf("%d. decode error: %v", i, err) continue } if got := buf.String(); tt.want != got { t.Errorf("%d. decode = %q; want %q", i, got, tt.want) } } } func TestAppendHuffmanString(t *testing.T) { tests := []struct { in, want string }{ {"www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"}, {"no-cache", "a8eb 1064 9cbf"}, {"custom-key", "25a8 49e9 5ba9 7d7f"}, {"custom-value", "25a8 49e9 5bb8 e8b4 bf"}, {"302", "6402"}, {"private", "aec3 771a 4b"}, {"Mon, 21 Oct 2013 20:13:21 GMT", "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"}, {"https://www.example.com", "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"}, {"gzip", "9bd9 ab"}, {"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", "94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07"}, } for i, tt := range tests { buf := []byte{} want := strings.Replace(tt.want, " ", "", -1) buf = AppendHuffmanString(buf, tt.in) if got := hex.EncodeToString(buf); want != got { t.Errorf("%d. encode = %q; want %q", i, got, want) } } } func TestHuffmanMaxStrLen(t *testing.T) { const msg = "Some string" huff := AppendHuffmanString(nil, msg) testGood := func(max int) { var out bytes.Buffer if err := huffmanDecode(&out, max, huff); err != nil { t.Errorf("For maxLen=%d, unexpected error: %v", max, err) } if out.String() != msg { t.Errorf("For maxLen=%d, out = %q; want %q", max, out.String(), msg) } } testGood(0) testGood(len(msg)) testGood(len(msg) + 1) var out bytes.Buffer if err := huffmanDecode(&out, len(msg)-1, huff); err != ErrStringLength { t.Errorf("err = %v; want ErrStringLength", err) } } func TestHuffmanRoundtripStress(t *testing.T) { const Len = 50 // of uncompressed string input := make([]byte, Len) var output bytes.Buffer var huff []byte n := 5000 if testing.Short() { n = 100 } seed := time.Now().UnixNano() t.Logf("Seed = %v", seed) src := rand.New(rand.NewSource(seed)) var encSize int64 for i := 0; i < n; i++ { for l := range input { input[l] = byte(src.Intn(256)) } huff = AppendHuffmanString(huff[:0], string(input)) encSize += int64(len(huff)) output.Reset() if err := huffmanDecode(&output, 0, huff); err != nil { t.Errorf("Failed to decode %q -> %q -> error %v", input, huff, err) continue } if !bytes.Equal(output.Bytes(), input) { t.Errorf("Roundtrip failure on %q -> %q -> %q", input, huff, output.Bytes()) } } t.Logf("Compressed size of original: %0.02f%% (%v -> %v)", 100*(float64(encSize)/(Len*float64(n))), Len*n, encSize) } func TestHuffmanDecodeFuzz(t *testing.T) { const Len = 50 // of compressed var buf, zbuf bytes.Buffer n := 5000 if testing.Short() { n = 100 } seed := time.Now().UnixNano() t.Logf("Seed = %v", seed) src := rand.New(rand.NewSource(seed)) numFail := 0 for i := 0; i < n; i++ { zbuf.Reset() if i == 0 { // Start with at least one invalid one. zbuf.WriteString("00\x91\xff\xff\xff\xff\xc8") } else { for l := 0; l < Len; l++ { zbuf.WriteByte(byte(src.Intn(256))) } } buf.Reset() if err := huffmanDecode(&buf, 0, zbuf.Bytes()); err != nil { if err == ErrInvalidHuffman { numFail++ continue } t.Errorf("Failed to decode %q: %v", zbuf.Bytes(), err) continue } } t.Logf("%0.02f%% are invalid (%d / %d)", 100*float64(numFail)/float64(n), numFail, n) if numFail < 1 { t.Error("expected at least one invalid huffman encoding (test starts with one)") } } func TestReadVarInt(t *testing.T) { type res struct { i uint64 consumed int err error } tests := []struct { n byte p []byte want res }{ // Fits in a byte: {1, []byte{0}, res{0, 1, nil}}, {2, []byte{2}, res{2, 1, nil}}, {3, []byte{6}, res{6, 1, nil}}, {4, []byte{14}, res{14, 1, nil}}, {5, []byte{30}, res{30, 1, nil}}, {6, []byte{62}, res{62, 1, nil}}, {7, []byte{126}, res{126, 1, nil}}, {8, []byte{254}, res{254, 1, nil}}, // Doesn't fit in a byte: {1, []byte{1}, res{0, 0, errNeedMore}}, {2, []byte{3}, res{0, 0, errNeedMore}}, {3, []byte{7}, res{0, 0, errNeedMore}}, {4, []byte{15}, res{0, 0, errNeedMore}}, {5, []byte{31}, res{0, 0, errNeedMore}}, {6, []byte{63}, res{0, 0, errNeedMore}}, {7, []byte{127}, res{0, 0, errNeedMore}}, {8, []byte{255}, res{0, 0, errNeedMore}}, // Ignoring top bits: {5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111 {5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100 {5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101 // Extra byte: {5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte // Short a byte: {5, []byte{191, 154}, res{0, 0, errNeedMore}}, // integer overflow: {1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}}, } for _, tt := range tests { i, remain, err := readVarInt(tt.n, tt.p) consumed := len(tt.p) - len(remain) got := res{i, consumed, err} if got != tt.want { t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want) } } } // Fuzz crash, originally reported at https://github.com/bradfitz/http2/issues/56 func TestHuffmanFuzzCrash(t *testing.T) { got, err := HuffmanDecodeToString([]byte("00\x91\xff\xff\xff\xff\xc8")) if got != "" { t.Errorf("Got %q; want empty string", got) } if err != ErrInvalidHuffman { t.Errorf("Err = %v; want ErrInvalidHuffman", err) } } func dehex(s string) []byte { s = strings.Replace(s, " ", "", -1) s = strings.Replace(s, "\n", "", -1) b, err := hex.DecodeString(s) if err != nil { panic(err) } return b } func TestEmitEnabled(t *testing.T) { var buf bytes.Buffer enc := NewEncoder(&buf) enc.WriteField(HeaderField{Name: "foo", Value: "bar"}) enc.WriteField(HeaderField{Name: "foo", Value: "bar"}) numCallback := 0 var dec *Decoder dec = NewDecoder(8<<20, func(HeaderField) { numCallback++ dec.SetEmitEnabled(false) }) if !dec.EmitEnabled() { t.Errorf("initial emit enabled = false; want true") } if _, err := dec.Write(buf.Bytes()); err != nil { t.Error(err) } if numCallback != 1 { t.Errorf("num callbacks = %d; want 1", numCallback) } if dec.EmitEnabled() { t.Errorf("emit enabled = true; want false") } } func TestSaveBufLimit(t *testing.T) { const maxStr = 1 << 10 var got []HeaderField dec := NewDecoder(initialHeaderTableSize, func(hf HeaderField) { got = append(got, hf) }) dec.SetMaxStringLength(maxStr) var frag []byte frag = append(frag[:0], encodeTypeByte(false, false)) frag = appendVarInt(frag, 7, 3) frag = append(frag, "foo"...) frag = appendVarInt(frag, 7, 3) frag = append(frag, "bar"...) if _, err := dec.Write(frag); err != nil { t.Fatal(err) } want := []HeaderField{{Name: "foo", Value: "bar"}} if !reflect.DeepEqual(got, want) { t.Errorf("After small writes, got %v; want %v", got, want) } frag = append(frag[:0], encodeTypeByte(false, false)) frag = appendVarInt(frag, 7, maxStr*3) frag = append(frag, make([]byte, maxStr*3)...) _, err := dec.Write(frag) if err != ErrStringLength { t.Fatalf("Write error = %v; want ErrStringLength", err) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/hpack/huffman.go000066400000000000000000000105701264464372400245450ustar00rootroot00000000000000// Copyright 2014 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 hpack import ( "bytes" "errors" "io" "sync" ) var bufPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } // HuffmanDecode decodes the string in v and writes the expanded // result to w, returning the number of bytes written to w and the // Write call's return value. At most one Write call is made. func HuffmanDecode(w io.Writer, v []byte) (int, error) { buf := bufPool.Get().(*bytes.Buffer) buf.Reset() defer bufPool.Put(buf) if err := huffmanDecode(buf, 0, v); err != nil { return 0, err } return w.Write(buf.Bytes()) } // HuffmanDecodeToString decodes the string in v. func HuffmanDecodeToString(v []byte) (string, error) { buf := bufPool.Get().(*bytes.Buffer) buf.Reset() defer bufPool.Put(buf) if err := huffmanDecode(buf, 0, v); err != nil { return "", err } return buf.String(), nil } // ErrInvalidHuffman is returned for errors found decoding // Huffman-encoded strings. var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data") // huffmanDecode decodes v to buf. // If maxLen is greater than 0, attempts to write more to buf than // maxLen bytes will return ErrStringLength. func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error { n := rootHuffmanNode cur, nbits := uint(0), uint8(0) for _, b := range v { cur = cur<<8 | uint(b) nbits += 8 for nbits >= 8 { idx := byte(cur >> (nbits - 8)) n = n.children[idx] if n == nil { return ErrInvalidHuffman } if n.children == nil { if maxLen != 0 && buf.Len() == maxLen { return ErrStringLength } buf.WriteByte(n.sym) nbits -= n.codeLen n = rootHuffmanNode } else { nbits -= 8 } } } for nbits > 0 { n = n.children[byte(cur<<(8-nbits))] if n.children != nil || n.codeLen > nbits { break } buf.WriteByte(n.sym) nbits -= n.codeLen n = rootHuffmanNode } return nil } type node struct { // children is non-nil for internal nodes children []*node // The following are only valid if children is nil: codeLen uint8 // number of bits that led to the output of sym sym byte // output symbol } func newInternalNode() *node { return &node{children: make([]*node, 256)} } var rootHuffmanNode = newInternalNode() func init() { if len(huffmanCodes) != 256 { panic("unexpected size") } for i, code := range huffmanCodes { addDecoderNode(byte(i), code, huffmanCodeLen[i]) } } func addDecoderNode(sym byte, code uint32, codeLen uint8) { cur := rootHuffmanNode for codeLen > 8 { codeLen -= 8 i := uint8(code >> codeLen) if cur.children[i] == nil { cur.children[i] = newInternalNode() } cur = cur.children[i] } shift := 8 - codeLen start, end := int(uint8(code<> (nbits - rembits)) dst[len(dst)-1] |= t } return dst } // HuffmanEncodeLength returns the number of bytes required to encode // s in Huffman codes. The result is round up to byte boundary. func HuffmanEncodeLength(s string) uint64 { n := uint64(0) for i := 0; i < len(s); i++ { n += uint64(huffmanCodeLen[s[i]]) } return (n + 7) / 8 } // appendByteToHuffmanCode appends Huffman code for c to dst and // returns the extended buffer and the remaining bits in the last // element. The appending is not byte aligned and the remaining bits // in the last element of dst is given in rembits. func appendByteToHuffmanCode(dst []byte, rembits uint8, c byte) ([]byte, uint8) { code := huffmanCodes[c] nbits := huffmanCodeLen[c] for { if rembits > nbits { t := uint8(code << (rembits - nbits)) dst[len(dst)-1] |= t rembits -= nbits break } t := uint8(code >> (nbits - rembits)) dst[len(dst)-1] |= t nbits -= rembits rembits = 8 if nbits == 0 { break } dst = append(dst, 0) } return dst, rembits } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/hpack/tables.go000066400000000000000000000126751264464372400244030ustar00rootroot00000000000000// Copyright 2014 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 hpack func pair(name, value string) HeaderField { return HeaderField{Name: name, Value: value} } // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B var staticTable = [...]HeaderField{ pair(":authority", ""), // index 1 (1-based) pair(":method", "GET"), pair(":method", "POST"), pair(":path", "/"), pair(":path", "/index.html"), pair(":scheme", "http"), pair(":scheme", "https"), pair(":status", "200"), pair(":status", "204"), pair(":status", "206"), pair(":status", "304"), pair(":status", "400"), pair(":status", "404"), pair(":status", "500"), pair("accept-charset", ""), pair("accept-encoding", "gzip, deflate"), pair("accept-language", ""), pair("accept-ranges", ""), pair("accept", ""), pair("access-control-allow-origin", ""), pair("age", ""), pair("allow", ""), pair("authorization", ""), pair("cache-control", ""), pair("content-disposition", ""), pair("content-encoding", ""), pair("content-language", ""), pair("content-length", ""), pair("content-location", ""), pair("content-range", ""), pair("content-type", ""), pair("cookie", ""), pair("date", ""), pair("etag", ""), pair("expect", ""), pair("expires", ""), pair("from", ""), pair("host", ""), pair("if-match", ""), pair("if-modified-since", ""), pair("if-none-match", ""), pair("if-range", ""), pair("if-unmodified-since", ""), pair("last-modified", ""), pair("link", ""), pair("location", ""), pair("max-forwards", ""), pair("proxy-authenticate", ""), pair("proxy-authorization", ""), pair("range", ""), pair("referer", ""), pair("refresh", ""), pair("retry-after", ""), pair("server", ""), pair("set-cookie", ""), pair("strict-transport-security", ""), pair("transfer-encoding", ""), pair("user-agent", ""), pair("vary", ""), pair("via", ""), pair("www-authenticate", ""), } var huffmanCodes = [256]uint32{ 0x1ff8, 0x7fffd8, 0xfffffe2, 0xfffffe3, 0xfffffe4, 0xfffffe5, 0xfffffe6, 0xfffffe7, 0xfffffe8, 0xffffea, 0x3ffffffc, 0xfffffe9, 0xfffffea, 0x3ffffffd, 0xfffffeb, 0xfffffec, 0xfffffed, 0xfffffee, 0xfffffef, 0xffffff0, 0xffffff1, 0xffffff2, 0x3ffffffe, 0xffffff3, 0xffffff4, 0xffffff5, 0xffffff6, 0xffffff7, 0xffffff8, 0xffffff9, 0xffffffa, 0xffffffb, 0x14, 0x3f8, 0x3f9, 0xffa, 0x1ff9, 0x15, 0xf8, 0x7fa, 0x3fa, 0x3fb, 0xf9, 0x7fb, 0xfa, 0x16, 0x17, 0x18, 0x0, 0x1, 0x2, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x5c, 0xfb, 0x7ffc, 0x20, 0xffb, 0x3fc, 0x1ffa, 0x21, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0xfc, 0x73, 0xfd, 0x1ffb, 0x7fff0, 0x1ffc, 0x3ffc, 0x22, 0x7ffd, 0x3, 0x23, 0x4, 0x24, 0x5, 0x25, 0x26, 0x27, 0x6, 0x74, 0x75, 0x28, 0x29, 0x2a, 0x7, 0x2b, 0x76, 0x2c, 0x8, 0x9, 0x2d, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7ffe, 0x7fc, 0x3ffd, 0x1ffd, 0xffffffc, 0xfffe6, 0x3fffd2, 0xfffe7, 0xfffe8, 0x3fffd3, 0x3fffd4, 0x3fffd5, 0x7fffd9, 0x3fffd6, 0x7fffda, 0x7fffdb, 0x7fffdc, 0x7fffdd, 0x7fffde, 0xffffeb, 0x7fffdf, 0xffffec, 0xffffed, 0x3fffd7, 0x7fffe0, 0xffffee, 0x7fffe1, 0x7fffe2, 0x7fffe3, 0x7fffe4, 0x1fffdc, 0x3fffd8, 0x7fffe5, 0x3fffd9, 0x7fffe6, 0x7fffe7, 0xffffef, 0x3fffda, 0x1fffdd, 0xfffe9, 0x3fffdb, 0x3fffdc, 0x7fffe8, 0x7fffe9, 0x1fffde, 0x7fffea, 0x3fffdd, 0x3fffde, 0xfffff0, 0x1fffdf, 0x3fffdf, 0x7fffeb, 0x7fffec, 0x1fffe0, 0x1fffe1, 0x3fffe0, 0x1fffe2, 0x7fffed, 0x3fffe1, 0x7fffee, 0x7fffef, 0xfffea, 0x3fffe2, 0x3fffe3, 0x3fffe4, 0x7ffff0, 0x3fffe5, 0x3fffe6, 0x7ffff1, 0x3ffffe0, 0x3ffffe1, 0xfffeb, 0x7fff1, 0x3fffe7, 0x7ffff2, 0x3fffe8, 0x1ffffec, 0x3ffffe2, 0x3ffffe3, 0x3ffffe4, 0x7ffffde, 0x7ffffdf, 0x3ffffe5, 0xfffff1, 0x1ffffed, 0x7fff2, 0x1fffe3, 0x3ffffe6, 0x7ffffe0, 0x7ffffe1, 0x3ffffe7, 0x7ffffe2, 0xfffff2, 0x1fffe4, 0x1fffe5, 0x3ffffe8, 0x3ffffe9, 0xffffffd, 0x7ffffe3, 0x7ffffe4, 0x7ffffe5, 0xfffec, 0xfffff3, 0xfffed, 0x1fffe6, 0x3fffe9, 0x1fffe7, 0x1fffe8, 0x7ffff3, 0x3fffea, 0x3fffeb, 0x1ffffee, 0x1ffffef, 0xfffff4, 0xfffff5, 0x3ffffea, 0x7ffff4, 0x3ffffeb, 0x7ffffe6, 0x3ffffec, 0x3ffffed, 0x7ffffe7, 0x7ffffe8, 0x7ffffe9, 0x7ffffea, 0x7ffffeb, 0xffffffe, 0x7ffffec, 0x7ffffed, 0x7ffffee, 0x7ffffef, 0x7fffff0, 0x3ffffee, } var huffmanCodeLen = [256]uint8{ 13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28, 6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10, 13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6, 15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5, 6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28, 20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23, 24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24, 22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23, 21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23, 26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25, 19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27, 20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23, 26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26, } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/http2.go000066400000000000000000000151631264464372400230770ustar00rootroot00000000000000// Copyright 2014 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 http2 implements the HTTP/2 protocol. // // This package is low-level and intended to be used directly by very // few people. Most users will use it indirectly through the automatic // use by the net/http package (from Go 1.6 and later). // For use in earlier Go versions see ConfigureServer. (Transport support // requires Go 1.6 or later) // // See https://http2.github.io/ for more information on HTTP/2. // // See https://http2.golang.org/ for a test server running this code. package http2 import ( "bufio" "fmt" "io" "net/http" "os" "strconv" "strings" "sync" ) var ( VerboseLogs bool logFrameWrites bool ) func init() { e := os.Getenv("GODEBUG") if strings.Contains(e, "http2debug=1") { VerboseLogs = true } if strings.Contains(e, "http2debug=2") { VerboseLogs = true logFrameWrites = true } } const ( // ClientPreface is the string that must be sent by new // connections from clients. ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" // SETTINGS_MAX_FRAME_SIZE default // http://http2.github.io/http2-spec/#rfc.section.6.5.2 initialMaxFrameSize = 16384 // NextProtoTLS is the NPN/ALPN protocol negotiated during // HTTP/2's TLS setup. NextProtoTLS = "h2" // http://http2.github.io/http2-spec/#SettingValues initialHeaderTableSize = 4096 initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size defaultMaxReadFrameSize = 1 << 20 ) var ( clientPreface = []byte(ClientPreface) ) type streamState int const ( stateIdle streamState = iota stateOpen stateHalfClosedLocal stateHalfClosedRemote stateResvLocal stateResvRemote stateClosed ) var stateName = [...]string{ stateIdle: "Idle", stateOpen: "Open", stateHalfClosedLocal: "HalfClosedLocal", stateHalfClosedRemote: "HalfClosedRemote", stateResvLocal: "ResvLocal", stateResvRemote: "ResvRemote", stateClosed: "Closed", } func (st streamState) String() string { return stateName[st] } // Setting is a setting parameter: which setting it is, and its value. type Setting struct { // ID is which setting is being set. // See http://http2.github.io/http2-spec/#SettingValues ID SettingID // Val is the value. Val uint32 } func (s Setting) String() string { return fmt.Sprintf("[%v = %d]", s.ID, s.Val) } // Valid reports whether the setting is valid. func (s Setting) Valid() error { // Limits and error codes from 6.5.2 Defined SETTINGS Parameters switch s.ID { case SettingEnablePush: if s.Val != 1 && s.Val != 0 { return ConnectionError(ErrCodeProtocol) } case SettingInitialWindowSize: if s.Val > 1<<31-1 { return ConnectionError(ErrCodeFlowControl) } case SettingMaxFrameSize: if s.Val < 16384 || s.Val > 1<<24-1 { return ConnectionError(ErrCodeProtocol) } } return nil } // A SettingID is an HTTP/2 setting as defined in // http://http2.github.io/http2-spec/#iana-settings type SettingID uint16 const ( SettingHeaderTableSize SettingID = 0x1 SettingEnablePush SettingID = 0x2 SettingMaxConcurrentStreams SettingID = 0x3 SettingInitialWindowSize SettingID = 0x4 SettingMaxFrameSize SettingID = 0x5 SettingMaxHeaderListSize SettingID = 0x6 ) var settingName = map[SettingID]string{ SettingHeaderTableSize: "HEADER_TABLE_SIZE", SettingEnablePush: "ENABLE_PUSH", SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS", SettingInitialWindowSize: "INITIAL_WINDOW_SIZE", SettingMaxFrameSize: "MAX_FRAME_SIZE", SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE", } func (s SettingID) String() string { if v, ok := settingName[s]; ok { return v } return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s)) } func validHeader(v string) bool { if len(v) == 0 { return false } for _, r := range v { // "Just as in HTTP/1.x, header field names are // strings of ASCII characters that are compared in a // case-insensitive fashion. However, header field // names MUST be converted to lowercase prior to their // encoding in HTTP/2. " if r >= 127 || ('A' <= r && r <= 'Z') { return false } } return true } var httpCodeStringCommon = map[int]string{} // n -> strconv.Itoa(n) func init() { for i := 100; i <= 999; i++ { if v := http.StatusText(i); v != "" { httpCodeStringCommon[i] = strconv.Itoa(i) } } } func httpCodeString(code int) string { if s, ok := httpCodeStringCommon[code]; ok { return s } return strconv.Itoa(code) } // from pkg io type stringWriter interface { WriteString(s string) (n int, err error) } // A gate lets two goroutines coordinate their activities. type gate chan struct{} func (g gate) Done() { g <- struct{}{} } func (g gate) Wait() { <-g } // A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed). type closeWaiter chan struct{} // Init makes a closeWaiter usable. // It exists because so a closeWaiter value can be placed inside a // larger struct and have the Mutex and Cond's memory in the same // allocation. func (cw *closeWaiter) Init() { *cw = make(chan struct{}) } // Close marks the closeWaiter as closed and unblocks any waiters. func (cw closeWaiter) Close() { close(cw) } // Wait waits for the closeWaiter to become closed. func (cw closeWaiter) Wait() { <-cw } // bufferedWriter is a buffered writer that writes to w. // Its buffered writer is lazily allocated as needed, to minimize // idle memory usage with many connections. type bufferedWriter struct { w io.Writer // immutable bw *bufio.Writer // non-nil when data is buffered } func newBufferedWriter(w io.Writer) *bufferedWriter { return &bufferedWriter{w: w} } var bufWriterPool = sync.Pool{ New: func() interface{} { // TODO: pick something better? this is a bit under // (3 x typical 1500 byte MTU) at least. return bufio.NewWriterSize(nil, 4<<10) }, } func (w *bufferedWriter) Write(p []byte) (n int, err error) { if w.bw == nil { bw := bufWriterPool.Get().(*bufio.Writer) bw.Reset(w.w) w.bw = bw } return w.bw.Write(p) } func (w *bufferedWriter) Flush() error { bw := w.bw if bw == nil { return nil } err := bw.Flush() bw.Reset(nil) bufWriterPool.Put(bw) w.bw = nil return err } func mustUint31(v int32) uint32 { if v < 0 || v > 2147483647 { panic("out of range") } return uint32(v) } // bodyAllowedForStatus reports whether a given response status code // permits a body. See RFC2616, section 4.4. func bodyAllowedForStatus(status int) bool { switch { case status >= 100 && status <= 199: return false case status == 204: return false case status == 304: return false } return true } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/http2_test.go000066400000000000000000000104751264464372400241370ustar00rootroot00000000000000// Copyright 2014 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 http2 import ( "bytes" "errors" "flag" "fmt" "net/http" "os/exec" "strconv" "strings" "testing" "golang.org/x/net/http2/hpack" ) var knownFailing = flag.Bool("known_failing", false, "Run known-failing tests.") func condSkipFailingTest(t *testing.T) { if !*knownFailing { t.Skip("Skipping known-failing test without --known_failing") } } func init() { DebugGoroutines = true flag.BoolVar(&VerboseLogs, "verboseh2", false, "Verbose HTTP/2 debug logging") } func TestSettingString(t *testing.T) { tests := []struct { s Setting want string }{ {Setting{SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"}, {Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"}, } for i, tt := range tests { got := fmt.Sprint(tt.s) if got != tt.want { t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want) } } } type twriter struct { t testing.TB st *serverTester // optional } func (w twriter) Write(p []byte) (n int, err error) { if w.st != nil { ps := string(p) for _, phrase := range w.st.logFilter { if strings.Contains(ps, phrase) { return len(p), nil // no logging } } } w.t.Logf("%s", p) return len(p), nil } // like encodeHeader, but don't add implicit psuedo headers. func encodeHeaderNoImplicit(t *testing.T, headers ...string) []byte { var buf bytes.Buffer enc := hpack.NewEncoder(&buf) for len(headers) > 0 { k, v := headers[0], headers[1] headers = headers[2:] if err := enc.WriteField(hpack.HeaderField{Name: k, Value: v}); err != nil { t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err) } } return buf.Bytes() } // Verify that curl has http2. func requireCurl(t *testing.T) { out, err := dockerLogs(curl(t, "--version")) if err != nil { t.Skipf("failed to determine curl features; skipping test") } if !strings.Contains(string(out), "HTTP2") { t.Skip("curl doesn't support HTTP2; skipping test") } } func curl(t *testing.T, args ...string) (container string) { out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "gohttp2/curl"}, args...)...).Output() if err != nil { t.Skipf("Failed to run curl in docker: %v, %s", err, out) } return strings.TrimSpace(string(out)) } // Verify that h2load exists. func requireH2load(t *testing.T) { out, err := dockerLogs(h2load(t, "--version")) if err != nil { t.Skipf("failed to probe h2load; skipping test: %s", out) } if !strings.Contains(string(out), "h2load nghttp2/") { t.Skipf("h2load not present; skipping test. (Output=%q)", out) } } func h2load(t *testing.T, args ...string) (container string) { out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl"}, args...)...).Output() if err != nil { t.Skipf("Failed to run h2load in docker: %v, %s", err, out) } return strings.TrimSpace(string(out)) } type puppetCommand struct { fn func(w http.ResponseWriter, r *http.Request) done chan<- bool } type handlerPuppet struct { ch chan puppetCommand } func newHandlerPuppet() *handlerPuppet { return &handlerPuppet{ ch: make(chan puppetCommand), } } func (p *handlerPuppet) act(w http.ResponseWriter, r *http.Request) { for cmd := range p.ch { cmd.fn(w, r) cmd.done <- true } } func (p *handlerPuppet) done() { close(p.ch) } func (p *handlerPuppet) do(fn func(http.ResponseWriter, *http.Request)) { done := make(chan bool) p.ch <- puppetCommand{fn, done} <-done } func dockerLogs(container string) ([]byte, error) { out, err := exec.Command("docker", "wait", container).CombinedOutput() if err != nil { return out, err } exitStatus, err := strconv.Atoi(strings.TrimSpace(string(out))) if err != nil { return out, errors.New("unexpected exit status from docker wait") } out, err = exec.Command("docker", "logs", container).CombinedOutput() exec.Command("docker", "rm", container).Run() if err == nil && exitStatus != 0 { err = fmt.Errorf("exit status %d: %s", exitStatus, out) } return out, err } func kill(container string) { exec.Command("docker", "kill", container).Run() exec.Command("docker", "rm", container).Run() } func cleanDate(res *http.Response) { if d := res.Header["Date"]; len(d) == 1 { d[0] = "XXX" } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/not_go15.go000066400000000000000000000004311264464372400234610ustar00rootroot00000000000000// Copyright 2015 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. // +build !go1.5 package http2 import "net/http" func requestCancel(req *http.Request) <-chan struct{} { return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/not_go16.go000066400000000000000000000004461264464372400234700ustar00rootroot00000000000000// Copyright 2015 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. // +build !go1.6 package http2 import "net/http" func configureTransport(t1 *http.Transport) error { return errTransportVersion } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/pipe.go000066400000000000000000000070261264464372400227720ustar00rootroot00000000000000// Copyright 2014 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 http2 import ( "errors" "io" "sync" ) // pipe is a goroutine-safe io.Reader/io.Writer pair. It's like // io.Pipe except there are no PipeReader/PipeWriter halves, and the // underlying buffer is an interface. (io.Pipe is always unbuffered) type pipe struct { mu sync.Mutex c sync.Cond // c.L lazily initialized to &p.mu b pipeBuffer err error // read error once empty. non-nil means closed. breakErr error // immediate read error (caller doesn't see rest of b) donec chan struct{} // closed on error readFn func() // optional code to run in Read before error } type pipeBuffer interface { Len() int io.Writer io.Reader } // Read waits until data is available and copies bytes // from the buffer into p. func (p *pipe) Read(d []byte) (n int, err error) { p.mu.Lock() defer p.mu.Unlock() if p.c.L == nil { p.c.L = &p.mu } for { if p.breakErr != nil { return 0, p.breakErr } if p.b.Len() > 0 { return p.b.Read(d) } if p.err != nil { if p.readFn != nil { p.readFn() // e.g. copy trailers p.readFn = nil // not sticky like p.err } return 0, p.err } p.c.Wait() } } var errClosedPipeWrite = errors.New("write on closed buffer") // Write copies bytes from p into the buffer and wakes a reader. // It is an error to write more data than the buffer can hold. func (p *pipe) Write(d []byte) (n int, err error) { p.mu.Lock() defer p.mu.Unlock() if p.c.L == nil { p.c.L = &p.mu } defer p.c.Signal() if p.err != nil { return 0, errClosedPipeWrite } return p.b.Write(d) } // CloseWithError causes the next Read (waking up a current blocked // Read if needed) to return the provided err after all data has been // read. // // The error must be non-nil. func (p *pipe) CloseWithError(err error) { p.closeWithError(&p.err, err, nil) } // BreakWithError causes the next Read (waking up a current blocked // Read if needed) to return the provided err immediately, without // waiting for unread data. func (p *pipe) BreakWithError(err error) { p.closeWithError(&p.breakErr, err, nil) } // closeWithErrorAndCode is like CloseWithError but also sets some code to run // in the caller's goroutine before returning the error. func (p *pipe) closeWithErrorAndCode(err error, fn func()) { p.closeWithError(&p.err, err, fn) } func (p *pipe) closeWithError(dst *error, err error, fn func()) { if err == nil { panic("err must be non-nil") } p.mu.Lock() defer p.mu.Unlock() if p.c.L == nil { p.c.L = &p.mu } defer p.c.Signal() if *dst != nil { // Already been done. return } p.readFn = fn *dst = err p.closeDoneLocked() } // requires p.mu be held. func (p *pipe) closeDoneLocked() { if p.donec == nil { return } // Close if unclosed. This isn't racy since we always // hold p.mu while closing. select { case <-p.donec: default: close(p.donec) } } // Err returns the error (if any) first set by BreakWithError or CloseWithError. func (p *pipe) Err() error { p.mu.Lock() defer p.mu.Unlock() if p.breakErr != nil { return p.breakErr } return p.err } // Done returns a channel which is closed if and when this pipe is closed // with CloseWithError. func (p *pipe) Done() <-chan struct{} { p.mu.Lock() defer p.mu.Unlock() if p.donec == nil { p.donec = make(chan struct{}) if p.err != nil || p.breakErr != nil { // Already hit an error. p.closeDoneLocked() } } return p.donec } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/pipe_test.go000066400000000000000000000036571264464372400240370ustar00rootroot00000000000000// Copyright 2014 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 http2 import ( "bytes" "errors" "io" "io/ioutil" "testing" ) func TestPipeClose(t *testing.T) { var p pipe p.b = new(bytes.Buffer) a := errors.New("a") b := errors.New("b") p.CloseWithError(a) p.CloseWithError(b) _, err := p.Read(make([]byte, 1)) if err != a { t.Errorf("err = %v want %v", err, a) } } func TestPipeDoneChan(t *testing.T) { var p pipe done := p.Done() select { case <-done: t.Fatal("done too soon") default: } p.CloseWithError(io.EOF) select { case <-done: default: t.Fatal("should be done") } } func TestPipeDoneChan_ErrFirst(t *testing.T) { var p pipe p.CloseWithError(io.EOF) done := p.Done() select { case <-done: default: t.Fatal("should be done") } } func TestPipeDoneChan_Break(t *testing.T) { var p pipe done := p.Done() select { case <-done: t.Fatal("done too soon") default: } p.BreakWithError(io.EOF) select { case <-done: default: t.Fatal("should be done") } } func TestPipeDoneChan_Break_ErrFirst(t *testing.T) { var p pipe p.BreakWithError(io.EOF) done := p.Done() select { case <-done: default: t.Fatal("should be done") } } func TestPipeCloseWithError(t *testing.T) { p := &pipe{b: new(bytes.Buffer)} const body = "foo" io.WriteString(p, body) a := errors.New("test error") p.CloseWithError(a) all, err := ioutil.ReadAll(p) if string(all) != body { t.Errorf("read bytes = %q; want %q", all, body) } if err != a { t.Logf("read error = %v, %v", err, a) } } func TestPipeBreakWithError(t *testing.T) { p := &pipe{b: new(bytes.Buffer)} io.WriteString(p, "foo") a := errors.New("test err") p.BreakWithError(a) all, err := ioutil.ReadAll(p) if string(all) != "" { t.Errorf("read bytes = %q; want empty string", all) } if err != a { t.Logf("read error = %v, %v", err, a) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/priority_test.go000066400000000000000000000045751264464372400247630ustar00rootroot00000000000000// Copyright 2014 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 http2 import ( "testing" ) func TestPriority(t *testing.T) { // A -> B // move A's parent to B streams := make(map[uint32]*stream) a := &stream{ parent: nil, weight: 16, } streams[1] = a b := &stream{ parent: a, weight: 16, } streams[2] = b adjustStreamPriority(streams, 1, PriorityParam{ Weight: 20, StreamDep: 2, }) if a.parent != b { t.Errorf("Expected A's parent to be B") } if a.weight != 20 { t.Errorf("Expected A's weight to be 20; got %d", a.weight) } if b.parent != nil { t.Errorf("Expected B to have no parent") } if b.weight != 16 { t.Errorf("Expected B's weight to be 16; got %d", b.weight) } } func TestPriorityExclusiveZero(t *testing.T) { // A B and C are all children of the 0 stream. // Exclusive reprioritization to any of the streams // should bring the rest of the streams under the // reprioritized stream streams := make(map[uint32]*stream) a := &stream{ parent: nil, weight: 16, } streams[1] = a b := &stream{ parent: nil, weight: 16, } streams[2] = b c := &stream{ parent: nil, weight: 16, } streams[3] = c adjustStreamPriority(streams, 3, PriorityParam{ Weight: 20, StreamDep: 0, Exclusive: true, }) if a.parent != c { t.Errorf("Expected A's parent to be C") } if a.weight != 16 { t.Errorf("Expected A's weight to be 16; got %d", a.weight) } if b.parent != c { t.Errorf("Expected B's parent to be C") } if b.weight != 16 { t.Errorf("Expected B's weight to be 16; got %d", b.weight) } if c.parent != nil { t.Errorf("Expected C to have no parent") } if c.weight != 20 { t.Errorf("Expected C's weight to be 20; got %d", b.weight) } } func TestPriorityOwnParent(t *testing.T) { streams := make(map[uint32]*stream) a := &stream{ parent: nil, weight: 16, } streams[1] = a b := &stream{ parent: a, weight: 16, } streams[2] = b adjustStreamPriority(streams, 1, PriorityParam{ Weight: 20, StreamDep: 1, }) if a.parent != nil { t.Errorf("Expected A's parent to be nil") } if a.weight != 20 { t.Errorf("Expected A's weight to be 20; got %d", a.weight) } if b.parent != a { t.Errorf("Expected B's parent to be A") } if b.weight != 16 { t.Errorf("Expected B's weight to be 16; got %d", b.weight) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/server.go000066400000000000000000001767471264464372400233640ustar00rootroot00000000000000// Copyright 2014 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. // TODO: replace all <-sc.doneServing with reads from the stream's cw // instead, and make sure that on close we close all open // streams. then remove doneServing? // TODO: re-audit GOAWAY support. Consider each incoming frame type and // whether it should be ignored during graceful shutdown. // TODO: disconnect idle clients. GFE seems to do 4 minutes. make // configurable? or maximum number of idle clients and remove the // oldest? // TODO: turn off the serve goroutine when idle, so // an idle conn only has the readFrames goroutine active. (which could // also be optimized probably to pin less memory in crypto/tls). This // would involve tracking when the serve goroutine is active (atomic // int32 read/CAS probably?) and starting it up when frames arrive, // and shutting it down when all handlers exit. the occasional PING // packets could use time.AfterFunc to call sc.wakeStartServeLoop() // (which is a no-op if already running) and then queue the PING write // as normal. The serve loop would then exit in most cases (if no // Handlers running) and not be woken up again until the PING packet // returns. // TODO (maybe): add a mechanism for Handlers to going into // half-closed-local mode (rw.(io.Closer) test?) but not exit their // handler, and continue to be able to read from the // Request.Body. This would be a somewhat semantic change from HTTP/1 // (or at least what we expose in net/http), so I'd probably want to // add it there too. For now, this package says that returning from // the Handler ServeHTTP function means you're both done reading and // done writing, without a way to stop just one or the other. package http2 import ( "bufio" "bytes" "crypto/tls" "errors" "fmt" "io" "log" "net" "net/http" "net/textproto" "net/url" "runtime" "strconv" "strings" "sync" "time" "golang.org/x/net/http2/hpack" ) const ( prefaceTimeout = 10 * time.Second firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway handlerChunkWriteSize = 4 << 10 defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to? ) var ( errClientDisconnected = errors.New("client disconnected") errClosedBody = errors.New("body closed by handler") errHandlerComplete = errors.New("http2: request body closed due to handler exiting") errStreamClosed = errors.New("http2: stream closed") ) var responseWriterStatePool = sync.Pool{ New: func() interface{} { rws := &responseWriterState{} rws.bw = bufio.NewWriterSize(chunkWriter{rws}, handlerChunkWriteSize) return rws }, } // Test hooks. var ( testHookOnConn func() testHookGetServerConn func(*serverConn) testHookOnPanicMu *sync.Mutex // nil except in tests testHookOnPanic func(sc *serverConn, panicVal interface{}) (rePanic bool) ) // Server is an HTTP/2 server. type Server struct { // MaxHandlers limits the number of http.Handler ServeHTTP goroutines // which may run at a time over all connections. // Negative or zero no limit. // TODO: implement MaxHandlers int // MaxConcurrentStreams optionally specifies the number of // concurrent streams that each client may have open at a // time. This is unrelated to the number of http.Handler goroutines // which may be active globally, which is MaxHandlers. // If zero, MaxConcurrentStreams defaults to at least 100, per // the HTTP/2 spec's recommendations. MaxConcurrentStreams uint32 // MaxReadFrameSize optionally specifies the largest frame // this server is willing to read. A valid value is between // 16k and 16M, inclusive. If zero or otherwise invalid, a // default value is used. MaxReadFrameSize uint32 // PermitProhibitedCipherSuites, if true, permits the use of // cipher suites prohibited by the HTTP/2 spec. PermitProhibitedCipherSuites bool } func (s *Server) maxReadFrameSize() uint32 { if v := s.MaxReadFrameSize; v >= minMaxFrameSize && v <= maxFrameSize { return v } return defaultMaxReadFrameSize } func (s *Server) maxConcurrentStreams() uint32 { if v := s.MaxConcurrentStreams; v > 0 { return v } return defaultMaxStreams } // ConfigureServer adds HTTP/2 support to a net/http Server. // // The configuration conf may be nil. // // ConfigureServer must be called before s begins serving. func ConfigureServer(s *http.Server, conf *Server) error { if conf == nil { conf = new(Server) } if s.TLSConfig == nil { s.TLSConfig = new(tls.Config) } else if s.TLSConfig.CipherSuites != nil { // If they already provided a CipherSuite list, return // an error if it has a bad order or is missing // ECDHE_RSA_WITH_AES_128_GCM_SHA256. const requiredCipher = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 haveRequired := false sawBad := false for i, cs := range s.TLSConfig.CipherSuites { if cs == requiredCipher { haveRequired = true } if isBadCipher(cs) { sawBad = true } else if sawBad { return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs) } } if !haveRequired { return fmt.Errorf("http2: TLSConfig.CipherSuites is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256") } } // Note: not setting MinVersion to tls.VersionTLS12, // as we don't want to interfere with HTTP/1.1 traffic // on the user's server. We enforce TLS 1.2 later once // we accept a connection. Ideally this should be done // during next-proto selection, but using TLS <1.2 with // HTTP/2 is still the client's bug. s.TLSConfig.PreferServerCipherSuites = true haveNPN := false for _, p := range s.TLSConfig.NextProtos { if p == NextProtoTLS { haveNPN = true break } } if !haveNPN { s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, NextProtoTLS) } // h2-14 is temporary (as of 2015-03-05) while we wait for all browsers // to switch to "h2". s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2-14") if s.TLSNextProto == nil { s.TLSNextProto = map[string]func(*http.Server, *tls.Conn, http.Handler){} } protoHandler := func(hs *http.Server, c *tls.Conn, h http.Handler) { if testHookOnConn != nil { testHookOnConn() } conf.handleConn(hs, c, h) } s.TLSNextProto[NextProtoTLS] = protoHandler s.TLSNextProto["h2-14"] = protoHandler // temporary; see above. return nil } func (srv *Server) handleConn(hs *http.Server, c net.Conn, h http.Handler) { sc := &serverConn{ srv: srv, hs: hs, conn: c, remoteAddrStr: c.RemoteAddr().String(), bw: newBufferedWriter(c), handler: h, streams: make(map[uint32]*stream), readFrameCh: make(chan readFrameResult), wantWriteFrameCh: make(chan frameWriteMsg, 8), wroteFrameCh: make(chan frameWriteResult, 1), // buffered; one send in writeFrameAsync bodyReadCh: make(chan bodyReadMsg), // buffering doesn't matter either way doneServing: make(chan struct{}), advMaxStreams: srv.maxConcurrentStreams(), writeSched: writeScheduler{ maxFrameSize: initialMaxFrameSize, }, initialWindowSize: initialWindowSize, headerTableSize: initialHeaderTableSize, serveG: newGoroutineLock(), pushEnabled: true, } sc.flow.add(initialWindowSize) sc.inflow.add(initialWindowSize) sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf) sc.hpackDecoder = hpack.NewDecoder(initialHeaderTableSize, nil) sc.hpackDecoder.SetMaxStringLength(sc.maxHeaderStringLen()) fr := NewFramer(sc.bw, c) fr.SetMaxReadFrameSize(srv.maxReadFrameSize()) sc.framer = fr if tc, ok := c.(*tls.Conn); ok { sc.tlsState = new(tls.ConnectionState) *sc.tlsState = tc.ConnectionState() // 9.2 Use of TLS Features // An implementation of HTTP/2 over TLS MUST use TLS // 1.2 or higher with the restrictions on feature set // and cipher suite described in this section. Due to // implementation limitations, it might not be // possible to fail TLS negotiation. An endpoint MUST // immediately terminate an HTTP/2 connection that // does not meet the TLS requirements described in // this section with a connection error (Section // 5.4.1) of type INADEQUATE_SECURITY. if sc.tlsState.Version < tls.VersionTLS12 { sc.rejectConn(ErrCodeInadequateSecurity, "TLS version too low") return } if sc.tlsState.ServerName == "" { // Client must use SNI, but we don't enforce that anymore, // since it was causing problems when connecting to bare IP // addresses during development. // // TODO: optionally enforce? Or enforce at the time we receive // a new request, and verify the the ServerName matches the :authority? // But that precludes proxy situations, perhaps. // // So for now, do nothing here again. } if !srv.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) { // "Endpoints MAY choose to generate a connection error // (Section 5.4.1) of type INADEQUATE_SECURITY if one of // the prohibited cipher suites are negotiated." // // We choose that. In my opinion, the spec is weak // here. It also says both parties must support at least // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 so there's no // excuses here. If we really must, we could allow an // "AllowInsecureWeakCiphers" option on the server later. // Let's see how it plays out first. sc.rejectConn(ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite)) return } } if hook := testHookGetServerConn; hook != nil { hook(sc) } sc.serve() } // isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec. func isBadCipher(cipher uint16) bool { switch cipher { case tls.TLS_RSA_WITH_RC4_128_SHA, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, tls.TLS_RSA_WITH_AES_128_CBC_SHA, tls.TLS_RSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: // Reject cipher suites from Appendix A. // "This list includes those cipher suites that do not // offer an ephemeral key exchange and those that are // based on the TLS null, stream or block cipher type" return true default: return false } } func (sc *serverConn) rejectConn(err ErrCode, debug string) { sc.vlogf("http2: server rejecting conn: %v, %s", err, debug) // ignoring errors. hanging up anyway. sc.framer.WriteGoAway(0, err, []byte(debug)) sc.bw.Flush() sc.conn.Close() } type serverConn struct { // Immutable: srv *Server hs *http.Server conn net.Conn bw *bufferedWriter // writing to conn handler http.Handler framer *Framer hpackDecoder *hpack.Decoder doneServing chan struct{} // closed when serverConn.serve ends readFrameCh chan readFrameResult // written by serverConn.readFrames wantWriteFrameCh chan frameWriteMsg // from handlers -> serve wroteFrameCh chan frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes bodyReadCh chan bodyReadMsg // from handlers -> serve testHookCh chan func(int) // code to run on the serve loop flow flow // conn-wide (not stream-specific) outbound flow control inflow flow // conn-wide inbound flow control tlsState *tls.ConnectionState // shared by all handlers, like net/http remoteAddrStr string // Everything following is owned by the serve loop; use serveG.check(): serveG goroutineLock // used to verify funcs are on serve() pushEnabled bool sawFirstSettings bool // got the initial SETTINGS frame after the preface needToSendSettingsAck bool unackedSettings int // how many SETTINGS have we sent without ACKs? clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit) advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client curOpenStreams uint32 // client's number of open streams maxStreamID uint32 // max ever seen streams map[uint32]*stream initialWindowSize int32 headerTableSize uint32 peerMaxHeaderListSize uint32 // zero means unknown (default) canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case req requestParam // non-zero while reading request headers writingFrame bool // started write goroutine but haven't heard back on wroteFrameCh needsFrameFlush bool // last frame write wasn't a flush writeSched writeScheduler inGoAway bool // we've started to or sent GOAWAY needToSendGoAway bool // we need to schedule a GOAWAY frame write goAwayCode ErrCode shutdownTimerCh <-chan time.Time // nil until used shutdownTimer *time.Timer // nil until used // Owned by the writeFrameAsync goroutine: headerWriteBuf bytes.Buffer hpackEncoder *hpack.Encoder } func (sc *serverConn) maxHeaderStringLen() int { v := sc.maxHeaderListSize() if uint32(int(v)) == v { return int(v) } // They had a crazy big number for MaxHeaderBytes anyway, // so give them unlimited header lengths: return 0 } func (sc *serverConn) maxHeaderListSize() uint32 { n := sc.hs.MaxHeaderBytes if n <= 0 { n = http.DefaultMaxHeaderBytes } // http2's count is in a slightly different unit and includes 32 bytes per pair. // So, take the net/http.Server value and pad it up a bit, assuming 10 headers. const perFieldOverhead = 32 // per http2 spec const typicalHeaders = 10 // conservative return uint32(n + typicalHeaders*perFieldOverhead) } // requestParam is the state of the next request, initialized over // potentially several frames HEADERS + zero or more CONTINUATION // frames. type requestParam struct { // stream is non-nil if we're reading (HEADER or CONTINUATION) // frames for a request (but not DATA). stream *stream header http.Header method, path string scheme, authority string sawRegularHeader bool // saw a non-pseudo header already invalidHeader bool // an invalid header was seen headerListSize int64 // actually uint32, but easier math this way } // stream represents a stream. This is the minimal metadata needed by // the serve goroutine. Most of the actual stream state is owned by // the http.Handler's goroutine in the responseWriter. Because the // responseWriter's responseWriterState is recycled at the end of a // handler, this struct intentionally has no pointer to the // *responseWriter{,State} itself, as the Handler ending nils out the // responseWriter's state field. type stream struct { // immutable: sc *serverConn id uint32 body *pipe // non-nil if expecting DATA frames cw closeWaiter // closed wait stream transitions to closed state // owned by serverConn's serve loop: bodyBytes int64 // body bytes seen so far declBodyBytes int64 // or -1 if undeclared flow flow // limits writing from Handler to client inflow flow // what the client is allowed to POST/etc to us parent *stream // or nil numTrailerValues int64 weight uint8 state streamState sentReset bool // only true once detached from streams map gotReset bool // only true once detacted from streams map gotTrailerHeader bool // HEADER frame for trailers was seen trailer http.Header // accumulated trailers reqTrailer http.Header // handler's Request.Trailer } func (sc *serverConn) Framer() *Framer { return sc.framer } func (sc *serverConn) CloseConn() error { return sc.conn.Close() } func (sc *serverConn) Flush() error { return sc.bw.Flush() } func (sc *serverConn) HeaderEncoder() (*hpack.Encoder, *bytes.Buffer) { return sc.hpackEncoder, &sc.headerWriteBuf } func (sc *serverConn) state(streamID uint32) (streamState, *stream) { sc.serveG.check() // http://http2.github.io/http2-spec/#rfc.section.5.1 if st, ok := sc.streams[streamID]; ok { return st.state, st } // "The first use of a new stream identifier implicitly closes all // streams in the "idle" state that might have been initiated by // that peer with a lower-valued stream identifier. For example, if // a client sends a HEADERS frame on stream 7 without ever sending a // frame on stream 5, then stream 5 transitions to the "closed" // state when the first frame for stream 7 is sent or received." if streamID <= sc.maxStreamID { return stateClosed, nil } return stateIdle, nil } // setConnState calls the net/http ConnState hook for this connection, if configured. // Note that the net/http package does StateNew and StateClosed for us. // There is currently no plan for StateHijacked or hijacking HTTP/2 connections. func (sc *serverConn) setConnState(state http.ConnState) { if sc.hs.ConnState != nil { sc.hs.ConnState(sc.conn, state) } } func (sc *serverConn) vlogf(format string, args ...interface{}) { if VerboseLogs { sc.logf(format, args...) } } func (sc *serverConn) logf(format string, args ...interface{}) { if lg := sc.hs.ErrorLog; lg != nil { lg.Printf(format, args...) } else { log.Printf(format, args...) } } func (sc *serverConn) condlogf(err error, format string, args ...interface{}) { if err == nil { return } str := err.Error() if err == io.EOF || strings.Contains(str, "use of closed network connection") { // Boring, expected errors. sc.vlogf(format, args...) } else { sc.logf(format, args...) } } func (sc *serverConn) onNewHeaderField(f hpack.HeaderField) { sc.serveG.check() if VerboseLogs { sc.vlogf("http2: server decoded %v", f) } switch { case !validHeader(f.Name): sc.req.invalidHeader = true case strings.HasPrefix(f.Name, ":"): if sc.req.sawRegularHeader { sc.logf("pseudo-header after regular header") sc.req.invalidHeader = true return } var dst *string switch f.Name { case ":method": dst = &sc.req.method case ":path": dst = &sc.req.path case ":scheme": dst = &sc.req.scheme case ":authority": dst = &sc.req.authority default: // 8.1.2.1 Pseudo-Header Fields // "Endpoints MUST treat a request or response // that contains undefined or invalid // pseudo-header fields as malformed (Section // 8.1.2.6)." sc.logf("invalid pseudo-header %q", f.Name) sc.req.invalidHeader = true return } if *dst != "" { sc.logf("duplicate pseudo-header %q sent", f.Name) sc.req.invalidHeader = true return } *dst = f.Value default: sc.req.sawRegularHeader = true sc.req.header.Add(sc.canonicalHeader(f.Name), f.Value) const headerFieldOverhead = 32 // per spec sc.req.headerListSize += int64(len(f.Name)) + int64(len(f.Value)) + headerFieldOverhead if sc.req.headerListSize > int64(sc.maxHeaderListSize()) { sc.hpackDecoder.SetEmitEnabled(false) } } } func (st *stream) onNewTrailerField(f hpack.HeaderField) { sc := st.sc sc.serveG.check() if VerboseLogs { sc.vlogf("http2: server decoded trailer %v", f) } switch { case !validHeader(f.Name): sc.req.invalidHeader = true return case strings.HasPrefix(f.Name, ":"): sc.req.invalidHeader = true return default: key := sc.canonicalHeader(f.Name) if st.trailer != nil { vv := append(st.trailer[key], f.Value) st.trailer[key] = vv // arbitrary; TODO: read spec about header list size limits wrt trailers const tooBig = 1000 if len(vv) >= tooBig { sc.hpackDecoder.SetEmitEnabled(false) } } } } func (sc *serverConn) canonicalHeader(v string) string { sc.serveG.check() cv, ok := commonCanonHeader[v] if ok { return cv } cv, ok = sc.canonHeader[v] if ok { return cv } if sc.canonHeader == nil { sc.canonHeader = make(map[string]string) } cv = http.CanonicalHeaderKey(v) sc.canonHeader[v] = cv return cv } type readFrameResult struct { f Frame // valid until readMore is called err error // readMore should be called once the consumer no longer needs or // retains f. After readMore, f is invalid and more frames can be // read. readMore func() } // readFrames is the loop that reads incoming frames. // It takes care to only read one frame at a time, blocking until the // consumer is done with the frame. // It's run on its own goroutine. func (sc *serverConn) readFrames() { gate := make(gate) for { f, err := sc.framer.ReadFrame() select { case sc.readFrameCh <- readFrameResult{f, err, gate.Done}: case <-sc.doneServing: return } select { case <-gate: case <-sc.doneServing: return } if terminalReadFrameError(err) { return } } } // frameWriteResult is the message passed from writeFrameAsync to the serve goroutine. type frameWriteResult struct { wm frameWriteMsg // what was written (or attempted) err error // result of the writeFrame call } // writeFrameAsync runs in its own goroutine and writes a single frame // and then reports when it's done. // At most one goroutine can be running writeFrameAsync at a time per // serverConn. func (sc *serverConn) writeFrameAsync(wm frameWriteMsg) { err := wm.write.writeFrame(sc) sc.wroteFrameCh <- frameWriteResult{wm, err} } func (sc *serverConn) closeAllStreamsOnConnClose() { sc.serveG.check() for _, st := range sc.streams { sc.closeStream(st, errClientDisconnected) } } func (sc *serverConn) stopShutdownTimer() { sc.serveG.check() if t := sc.shutdownTimer; t != nil { t.Stop() } } func (sc *serverConn) notePanic() { // Note: this is for serverConn.serve panicking, not http.Handler code. if testHookOnPanicMu != nil { testHookOnPanicMu.Lock() defer testHookOnPanicMu.Unlock() } if testHookOnPanic != nil { if e := recover(); e != nil { if testHookOnPanic(sc, e) { panic(e) } } } } func (sc *serverConn) serve() { sc.serveG.check() defer sc.notePanic() defer sc.conn.Close() defer sc.closeAllStreamsOnConnClose() defer sc.stopShutdownTimer() defer close(sc.doneServing) // unblocks handlers trying to send if VerboseLogs { sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs) } sc.writeFrame(frameWriteMsg{ write: writeSettings{ {SettingMaxFrameSize, sc.srv.maxReadFrameSize()}, {SettingMaxConcurrentStreams, sc.advMaxStreams}, {SettingMaxHeaderListSize, sc.maxHeaderListSize()}, // TODO: more actual settings, notably // SettingInitialWindowSize, but then we also // want to bump up the conn window size the // same amount here right after the settings }, }) sc.unackedSettings++ if err := sc.readPreface(); err != nil { sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err) return } // Now that we've got the preface, get us out of the // "StateNew" state. We can't go directly to idle, though. // Active means we read some data and anticipate a request. We'll // do another Active when we get a HEADERS frame. sc.setConnState(http.StateActive) sc.setConnState(http.StateIdle) go sc.readFrames() // closed by defer sc.conn.Close above settingsTimer := time.NewTimer(firstSettingsTimeout) loopNum := 0 for { loopNum++ select { case wm := <-sc.wantWriteFrameCh: sc.writeFrame(wm) case res := <-sc.wroteFrameCh: sc.wroteFrame(res) case res := <-sc.readFrameCh: if !sc.processFrameFromReader(res) { return } res.readMore() if settingsTimer.C != nil { settingsTimer.Stop() settingsTimer.C = nil } case m := <-sc.bodyReadCh: sc.noteBodyRead(m.st, m.n) case <-settingsTimer.C: sc.logf("timeout waiting for SETTINGS frames from %v", sc.conn.RemoteAddr()) return case <-sc.shutdownTimerCh: sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr()) return case fn := <-sc.testHookCh: fn(loopNum) } } } // readPreface reads the ClientPreface greeting from the peer // or returns an error on timeout or an invalid greeting. func (sc *serverConn) readPreface() error { errc := make(chan error, 1) go func() { // Read the client preface buf := make([]byte, len(ClientPreface)) if _, err := io.ReadFull(sc.conn, buf); err != nil { errc <- err } else if !bytes.Equal(buf, clientPreface) { errc <- fmt.Errorf("bogus greeting %q", buf) } else { errc <- nil } }() timer := time.NewTimer(prefaceTimeout) // TODO: configurable on *Server? defer timer.Stop() select { case <-timer.C: return errors.New("timeout waiting for client preface") case err := <-errc: if err == nil { if VerboseLogs { sc.vlogf("http2: server: client %v said hello", sc.conn.RemoteAddr()) } } return err } } var errChanPool = sync.Pool{ New: func() interface{} { return make(chan error, 1) }, } var writeDataPool = sync.Pool{ New: func() interface{} { return new(writeData) }, } // writeDataFromHandler writes DATA response frames from a handler on // the given stream. func (sc *serverConn) writeDataFromHandler(stream *stream, data []byte, endStream bool) error { ch := errChanPool.Get().(chan error) writeArg := writeDataPool.Get().(*writeData) *writeArg = writeData{stream.id, data, endStream} err := sc.writeFrameFromHandler(frameWriteMsg{ write: writeArg, stream: stream, done: ch, }) if err != nil { return err } var frameWriteDone bool // the frame write is done (successfully or not) select { case err = <-ch: frameWriteDone = true case <-sc.doneServing: return errClientDisconnected case <-stream.cw: // If both ch and stream.cw were ready (as might // happen on the final Write after an http.Handler // ends), prefer the write result. Otherwise this // might just be us successfully closing the stream. // The writeFrameAsync and serve goroutines guarantee // that the ch send will happen before the stream.cw // close. select { case err = <-ch: frameWriteDone = true default: return errStreamClosed } } errChanPool.Put(ch) if frameWriteDone { writeDataPool.Put(writeArg) } return err } // writeFrameFromHandler sends wm to sc.wantWriteFrameCh, but aborts // if the connection has gone away. // // This must not be run from the serve goroutine itself, else it might // deadlock writing to sc.wantWriteFrameCh (which is only mildly // buffered and is read by serve itself). If you're on the serve // goroutine, call writeFrame instead. func (sc *serverConn) writeFrameFromHandler(wm frameWriteMsg) error { sc.serveG.checkNotOn() // NOT select { case sc.wantWriteFrameCh <- wm: return nil case <-sc.doneServing: // Serve loop is gone. // Client has closed their connection to the server. return errClientDisconnected } } // writeFrame schedules a frame to write and sends it if there's nothing // already being written. // // There is no pushback here (the serve goroutine never blocks). It's // the http.Handlers that block, waiting for their previous frames to // make it onto the wire // // If you're not on the serve goroutine, use writeFrameFromHandler instead. func (sc *serverConn) writeFrame(wm frameWriteMsg) { sc.serveG.check() sc.writeSched.add(wm) sc.scheduleFrameWrite() } // startFrameWrite starts a goroutine to write wm (in a separate // goroutine since that might block on the network), and updates the // serve goroutine's state about the world, updated from info in wm. func (sc *serverConn) startFrameWrite(wm frameWriteMsg) { sc.serveG.check() if sc.writingFrame { panic("internal error: can only be writing one frame at a time") } st := wm.stream if st != nil { switch st.state { case stateHalfClosedLocal: panic("internal error: attempt to send frame on half-closed-local stream") case stateClosed: if st.sentReset || st.gotReset { // Skip this frame. sc.scheduleFrameWrite() return } panic(fmt.Sprintf("internal error: attempt to send a write %v on a closed stream", wm)) } } sc.writingFrame = true sc.needsFrameFlush = true go sc.writeFrameAsync(wm) } // errHandlerPanicked is the error given to any callers blocked in a read from // Request.Body when the main goroutine panics. Since most handlers read in the // the main ServeHTTP goroutine, this will show up rarely. var errHandlerPanicked = errors.New("http2: handler panicked") // wroteFrame is called on the serve goroutine with the result of // whatever happened on writeFrameAsync. func (sc *serverConn) wroteFrame(res frameWriteResult) { sc.serveG.check() if !sc.writingFrame { panic("internal error: expected to be already writing a frame") } sc.writingFrame = false wm := res.wm st := wm.stream closeStream := endsStream(wm.write) if _, ok := wm.write.(handlerPanicRST); ok { sc.closeStream(st, errHandlerPanicked) } // Reply (if requested) to the blocked ServeHTTP goroutine. if ch := wm.done; ch != nil { select { case ch <- res.err: default: panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wm.write)) } } wm.write = nil // prevent use (assume it's tainted after wm.done send) if closeStream { if st == nil { panic("internal error: expecting non-nil stream") } switch st.state { case stateOpen: // Here we would go to stateHalfClosedLocal in // theory, but since our handler is done and // the net/http package provides no mechanism // for finishing writing to a ResponseWriter // while still reading data (see possible TODO // at top of this file), we go into closed // state here anyway, after telling the peer // we're hanging up on them. st.state = stateHalfClosedLocal // won't last long, but necessary for closeStream via resetStream errCancel := StreamError{st.id, ErrCodeCancel} sc.resetStream(errCancel) case stateHalfClosedRemote: sc.closeStream(st, errHandlerComplete) } } sc.scheduleFrameWrite() } // scheduleFrameWrite tickles the frame writing scheduler. // // If a frame is already being written, nothing happens. This will be called again // when the frame is done being written. // // If a frame isn't being written we need to send one, the best frame // to send is selected, preferring first things that aren't // stream-specific (e.g. ACKing settings), and then finding the // highest priority stream. // // If a frame isn't being written and there's nothing else to send, we // flush the write buffer. func (sc *serverConn) scheduleFrameWrite() { sc.serveG.check() if sc.writingFrame { return } if sc.needToSendGoAway { sc.needToSendGoAway = false sc.startFrameWrite(frameWriteMsg{ write: &writeGoAway{ maxStreamID: sc.maxStreamID, code: sc.goAwayCode, }, }) return } if sc.needToSendSettingsAck { sc.needToSendSettingsAck = false sc.startFrameWrite(frameWriteMsg{write: writeSettingsAck{}}) return } if !sc.inGoAway { if wm, ok := sc.writeSched.take(); ok { sc.startFrameWrite(wm) return } } if sc.needsFrameFlush { sc.startFrameWrite(frameWriteMsg{write: flushFrameWriter{}}) sc.needsFrameFlush = false // after startFrameWrite, since it sets this true return } } func (sc *serverConn) goAway(code ErrCode) { sc.serveG.check() if sc.inGoAway { return } if code != ErrCodeNo { sc.shutDownIn(250 * time.Millisecond) } else { // TODO: configurable sc.shutDownIn(1 * time.Second) } sc.inGoAway = true sc.needToSendGoAway = true sc.goAwayCode = code sc.scheduleFrameWrite() } func (sc *serverConn) shutDownIn(d time.Duration) { sc.serveG.check() sc.shutdownTimer = time.NewTimer(d) sc.shutdownTimerCh = sc.shutdownTimer.C } func (sc *serverConn) resetStream(se StreamError) { sc.serveG.check() sc.writeFrame(frameWriteMsg{write: se}) if st, ok := sc.streams[se.StreamID]; ok { st.sentReset = true sc.closeStream(st, se) } } // processFrameFromReader processes the serve loop's read from readFrameCh from the // frame-reading goroutine. // processFrameFromReader returns whether the connection should be kept open. func (sc *serverConn) processFrameFromReader(res readFrameResult) bool { sc.serveG.check() err := res.err if err != nil { if err == ErrFrameTooLarge { sc.goAway(ErrCodeFrameSize) return true // goAway will close the loop } clientGone := err == io.EOF || strings.Contains(err.Error(), "use of closed network connection") if clientGone { // TODO: could we also get into this state if // the peer does a half close // (e.g. CloseWrite) because they're done // sending frames but they're still wanting // our open replies? Investigate. // TODO: add CloseWrite to crypto/tls.Conn first // so we have a way to test this? I suppose // just for testing we could have a non-TLS mode. return false } } else { f := res.f if VerboseLogs { sc.vlogf("http2: server read frame %v", summarizeFrame(f)) } err = sc.processFrame(f) if err == nil { return true } } switch ev := err.(type) { case StreamError: sc.resetStream(ev) return true case goAwayFlowError: sc.goAway(ErrCodeFlowControl) return true case ConnectionError: sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev) sc.goAway(ErrCode(ev)) return true // goAway will handle shutdown default: if res.err != nil { sc.logf("http2: server closing client connection; error reading frame from client %s: %v", sc.conn.RemoteAddr(), err) } else { sc.logf("http2: server closing client connection: %v", err) } return false } } func (sc *serverConn) processFrame(f Frame) error { sc.serveG.check() // First frame received must be SETTINGS. if !sc.sawFirstSettings { if _, ok := f.(*SettingsFrame); !ok { return ConnectionError(ErrCodeProtocol) } sc.sawFirstSettings = true } switch f := f.(type) { case *SettingsFrame: return sc.processSettings(f) case *HeadersFrame: return sc.processHeaders(f) case *ContinuationFrame: return sc.processContinuation(f) case *WindowUpdateFrame: return sc.processWindowUpdate(f) case *PingFrame: return sc.processPing(f) case *DataFrame: return sc.processData(f) case *RSTStreamFrame: return sc.processResetStream(f) case *PriorityFrame: return sc.processPriority(f) case *PushPromiseFrame: // A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE // frame as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. return ConnectionError(ErrCodeProtocol) default: sc.vlogf("http2: server ignoring frame: %v", f.Header()) return nil } } func (sc *serverConn) processPing(f *PingFrame) error { sc.serveG.check() if f.IsAck() { // 6.7 PING: " An endpoint MUST NOT respond to PING frames // containing this flag." return nil } if f.StreamID != 0 { // "PING frames are not associated with any individual // stream. If a PING frame is received with a stream // identifier field value other than 0x0, the recipient MUST // respond with a connection error (Section 5.4.1) of type // PROTOCOL_ERROR." return ConnectionError(ErrCodeProtocol) } sc.writeFrame(frameWriteMsg{write: writePingAck{f}}) return nil } func (sc *serverConn) processWindowUpdate(f *WindowUpdateFrame) error { sc.serveG.check() switch { case f.StreamID != 0: // stream-level flow control st := sc.streams[f.StreamID] if st == nil { // "WINDOW_UPDATE can be sent by a peer that has sent a // frame bearing the END_STREAM flag. This means that a // receiver could receive a WINDOW_UPDATE frame on a "half // closed (remote)" or "closed" stream. A receiver MUST // NOT treat this as an error, see Section 5.1." return nil } if !st.flow.add(int32(f.Increment)) { return StreamError{f.StreamID, ErrCodeFlowControl} } default: // connection-level flow control if !sc.flow.add(int32(f.Increment)) { return goAwayFlowError{} } } sc.scheduleFrameWrite() return nil } func (sc *serverConn) processResetStream(f *RSTStreamFrame) error { sc.serveG.check() state, st := sc.state(f.StreamID) if state == stateIdle { // 6.4 "RST_STREAM frames MUST NOT be sent for a // stream in the "idle" state. If a RST_STREAM frame // identifying an idle stream is received, the // recipient MUST treat this as a connection error // (Section 5.4.1) of type PROTOCOL_ERROR. return ConnectionError(ErrCodeProtocol) } if st != nil { st.gotReset = true sc.closeStream(st, StreamError{f.StreamID, f.ErrCode}) } return nil } func (sc *serverConn) closeStream(st *stream, err error) { sc.serveG.check() if st.state == stateIdle || st.state == stateClosed { panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state)) } st.state = stateClosed sc.curOpenStreams-- if sc.curOpenStreams == 0 { sc.setConnState(http.StateIdle) } delete(sc.streams, st.id) if p := st.body; p != nil { p.CloseWithError(err) } st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc sc.writeSched.forgetStream(st.id) } func (sc *serverConn) processSettings(f *SettingsFrame) error { sc.serveG.check() if f.IsAck() { sc.unackedSettings-- if sc.unackedSettings < 0 { // Why is the peer ACKing settings we never sent? // The spec doesn't mention this case, but // hang up on them anyway. return ConnectionError(ErrCodeProtocol) } return nil } if err := f.ForeachSetting(sc.processSetting); err != nil { return err } sc.needToSendSettingsAck = true sc.scheduleFrameWrite() return nil } func (sc *serverConn) processSetting(s Setting) error { sc.serveG.check() if err := s.Valid(); err != nil { return err } if VerboseLogs { sc.vlogf("http2: server processing setting %v", s) } switch s.ID { case SettingHeaderTableSize: sc.headerTableSize = s.Val sc.hpackEncoder.SetMaxDynamicTableSize(s.Val) case SettingEnablePush: sc.pushEnabled = s.Val != 0 case SettingMaxConcurrentStreams: sc.clientMaxStreams = s.Val case SettingInitialWindowSize: return sc.processSettingInitialWindowSize(s.Val) case SettingMaxFrameSize: sc.writeSched.maxFrameSize = s.Val case SettingMaxHeaderListSize: sc.peerMaxHeaderListSize = s.Val default: // Unknown setting: "An endpoint that receives a SETTINGS // frame with any unknown or unsupported identifier MUST // ignore that setting." if VerboseLogs { sc.vlogf("http2: server ignoring unknown setting %v", s) } } return nil } func (sc *serverConn) processSettingInitialWindowSize(val uint32) error { sc.serveG.check() // Note: val already validated to be within range by // processSetting's Valid call. // "A SETTINGS frame can alter the initial flow control window // size for all current streams. When the value of // SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST // adjust the size of all stream flow control windows that it // maintains by the difference between the new value and the // old value." old := sc.initialWindowSize sc.initialWindowSize = int32(val) growth := sc.initialWindowSize - old // may be negative for _, st := range sc.streams { if !st.flow.add(growth) { // 6.9.2 Initial Flow Control Window Size // "An endpoint MUST treat a change to // SETTINGS_INITIAL_WINDOW_SIZE that causes any flow // control window to exceed the maximum size as a // connection error (Section 5.4.1) of type // FLOW_CONTROL_ERROR." return ConnectionError(ErrCodeFlowControl) } } return nil } func (sc *serverConn) processData(f *DataFrame) error { sc.serveG.check() // "If a DATA frame is received whose stream is not in "open" // or "half closed (local)" state, the recipient MUST respond // with a stream error (Section 5.4.2) of type STREAM_CLOSED." id := f.Header().StreamID st, ok := sc.streams[id] if !ok || st.state != stateOpen || st.gotTrailerHeader { // This includes sending a RST_STREAM if the stream is // in stateHalfClosedLocal (which currently means that // the http.Handler returned, so it's done reading & // done writing). Try to stop the client from sending // more DATA. return StreamError{id, ErrCodeStreamClosed} } if st.body == nil { panic("internal error: should have a body in this state") } data := f.Data() // Sender sending more than they'd declared? if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes { st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes)) return StreamError{id, ErrCodeStreamClosed} } if len(data) > 0 { // Check whether the client has flow control quota. if int(st.inflow.available()) < len(data) { return StreamError{id, ErrCodeFlowControl} } st.inflow.take(int32(len(data))) wrote, err := st.body.Write(data) if err != nil { return StreamError{id, ErrCodeStreamClosed} } if wrote != len(data) { panic("internal error: bad Writer") } st.bodyBytes += int64(len(data)) } if f.StreamEnded() { st.endStream() } return nil } // endStream closes a Request.Body's pipe. It is called when a DATA // frame says a request body is over (or after trailers). func (st *stream) endStream() { sc := st.sc sc.serveG.check() if st.declBodyBytes != -1 && st.declBodyBytes != st.bodyBytes { st.body.CloseWithError(fmt.Errorf("request declared a Content-Length of %d but only wrote %d bytes", st.declBodyBytes, st.bodyBytes)) } else { st.body.closeWithErrorAndCode(io.EOF, st.copyTrailersToHandlerRequest) st.body.CloseWithError(io.EOF) } st.state = stateHalfClosedRemote } // copyTrailersToHandlerRequest is run in the Handler's goroutine in // its Request.Body.Read just before it gets io.EOF. func (st *stream) copyTrailersToHandlerRequest() { for k, vv := range st.trailer { if _, ok := st.reqTrailer[k]; ok { // Only copy it over it was pre-declared. st.reqTrailer[k] = vv } } } func (sc *serverConn) processHeaders(f *HeadersFrame) error { sc.serveG.check() id := f.Header().StreamID if sc.inGoAway { // Ignore. return nil } // http://http2.github.io/http2-spec/#rfc.section.5.1.1 // Streams initiated by a client MUST use odd-numbered stream // identifiers. [...] An endpoint that receives an unexpected // stream identifier MUST respond with a connection error // (Section 5.4.1) of type PROTOCOL_ERROR. if id%2 != 1 { return ConnectionError(ErrCodeProtocol) } // A HEADERS frame can be used to create a new stream or // send a trailer for an open one. If we already have a stream // open, let it process its own HEADERS frame (trailers at this // point, if it's valid). st := sc.streams[f.Header().StreamID] if st != nil { return st.processTrailerHeaders(f) } // [...] The identifier of a newly established stream MUST be // numerically greater than all streams that the initiating // endpoint has opened or reserved. [...] An endpoint that // receives an unexpected stream identifier MUST respond with // a connection error (Section 5.4.1) of type PROTOCOL_ERROR. if id <= sc.maxStreamID || sc.req.stream != nil { return ConnectionError(ErrCodeProtocol) } if id > sc.maxStreamID { sc.maxStreamID = id } st = &stream{ sc: sc, id: id, state: stateOpen, } if f.StreamEnded() { st.state = stateHalfClosedRemote } st.cw.Init() st.flow.conn = &sc.flow // link to conn-level counter st.flow.add(sc.initialWindowSize) st.inflow.conn = &sc.inflow // link to conn-level counter st.inflow.add(initialWindowSize) // TODO: update this when we send a higher initial window size in the initial settings sc.streams[id] = st if f.HasPriority() { adjustStreamPriority(sc.streams, st.id, f.Priority) } sc.curOpenStreams++ if sc.curOpenStreams == 1 { sc.setConnState(http.StateActive) } sc.req = requestParam{ stream: st, header: make(http.Header), } sc.hpackDecoder.SetEmitFunc(sc.onNewHeaderField) sc.hpackDecoder.SetEmitEnabled(true) return sc.processHeaderBlockFragment(st, f.HeaderBlockFragment(), f.HeadersEnded()) } func (st *stream) processTrailerHeaders(f *HeadersFrame) error { sc := st.sc sc.serveG.check() if st.gotTrailerHeader { return ConnectionError(ErrCodeProtocol) } st.gotTrailerHeader = true if !f.StreamEnded() { return StreamError{st.id, ErrCodeProtocol} } sc.resetPendingRequest() // we use invalidHeader from it for trailers return st.processTrailerHeaderBlockFragment(f.HeaderBlockFragment(), f.HeadersEnded()) } func (sc *serverConn) processContinuation(f *ContinuationFrame) error { sc.serveG.check() st := sc.streams[f.Header().StreamID] if st.gotTrailerHeader { return st.processTrailerHeaderBlockFragment(f.HeaderBlockFragment(), f.HeadersEnded()) } return sc.processHeaderBlockFragment(st, f.HeaderBlockFragment(), f.HeadersEnded()) } func (sc *serverConn) processHeaderBlockFragment(st *stream, frag []byte, end bool) error { sc.serveG.check() if _, err := sc.hpackDecoder.Write(frag); err != nil { return ConnectionError(ErrCodeCompression) } if !end { return nil } if err := sc.hpackDecoder.Close(); err != nil { return ConnectionError(ErrCodeCompression) } defer sc.resetPendingRequest() if sc.curOpenStreams > sc.advMaxStreams { // "Endpoints MUST NOT exceed the limit set by their // peer. An endpoint that receives a HEADERS frame // that causes their advertised concurrent stream // limit to be exceeded MUST treat this as a stream // error (Section 5.4.2) of type PROTOCOL_ERROR or // REFUSED_STREAM." if sc.unackedSettings == 0 { // They should know better. return StreamError{st.id, ErrCodeProtocol} } // Assume it's a network race, where they just haven't // received our last SETTINGS update. But actually // this can't happen yet, because we don't yet provide // a way for users to adjust server parameters at // runtime. return StreamError{st.id, ErrCodeRefusedStream} } rw, req, err := sc.newWriterAndRequest() if err != nil { return err } st.reqTrailer = req.Trailer if st.reqTrailer != nil { st.trailer = make(http.Header) } st.body = req.Body.(*requestBody).pipe // may be nil st.declBodyBytes = req.ContentLength handler := sc.handler.ServeHTTP if !sc.hpackDecoder.EmitEnabled() { // Their header list was too long. Send a 431 error. handler = handleHeaderListTooLong } go sc.runHandler(rw, req, handler) return nil } func (st *stream) processTrailerHeaderBlockFragment(frag []byte, end bool) error { sc := st.sc sc.serveG.check() sc.hpackDecoder.SetEmitFunc(st.onNewTrailerField) if _, err := sc.hpackDecoder.Write(frag); err != nil { return ConnectionError(ErrCodeCompression) } if !end { return nil } rp := &sc.req if rp.invalidHeader { return StreamError{rp.stream.id, ErrCodeProtocol} } err := sc.hpackDecoder.Close() st.endStream() if err != nil { return ConnectionError(ErrCodeCompression) } return nil } func (sc *serverConn) processPriority(f *PriorityFrame) error { adjustStreamPriority(sc.streams, f.StreamID, f.PriorityParam) return nil } func adjustStreamPriority(streams map[uint32]*stream, streamID uint32, priority PriorityParam) { st, ok := streams[streamID] if !ok { // TODO: not quite correct (this streamID might // already exist in the dep tree, but be closed), but // close enough for now. return } st.weight = priority.Weight parent := streams[priority.StreamDep] // might be nil if parent == st { // if client tries to set this stream to be the parent of itself // ignore and keep going return } // section 5.3.3: If a stream is made dependent on one of its // own dependencies, the formerly dependent stream is first // moved to be dependent on the reprioritized stream's previous // parent. The moved dependency retains its weight. for piter := parent; piter != nil; piter = piter.parent { if piter == st { parent.parent = st.parent break } } st.parent = parent if priority.Exclusive && (st.parent != nil || priority.StreamDep == 0) { for _, openStream := range streams { if openStream != st && openStream.parent == st.parent { openStream.parent = st } } } } // resetPendingRequest zeros out all state related to a HEADERS frame // and its zero or more CONTINUATION frames sent to start a new // request. func (sc *serverConn) resetPendingRequest() { sc.serveG.check() sc.req = requestParam{} } func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, error) { sc.serveG.check() rp := &sc.req if rp.invalidHeader { return nil, nil, StreamError{rp.stream.id, ErrCodeProtocol} } isConnect := rp.method == "CONNECT" if isConnect { if rp.path != "" || rp.scheme != "" || rp.authority == "" { return nil, nil, StreamError{rp.stream.id, ErrCodeProtocol} } } else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") { // See 8.1.2.6 Malformed Requests and Responses: // // Malformed requests or responses that are detected // MUST be treated as a stream error (Section 5.4.2) // of type PROTOCOL_ERROR." // // 8.1.2.3 Request Pseudo-Header Fields // "All HTTP/2 requests MUST include exactly one valid // value for the :method, :scheme, and :path // pseudo-header fields" return nil, nil, StreamError{rp.stream.id, ErrCodeProtocol} } bodyOpen := rp.stream.state == stateOpen if rp.method == "HEAD" && bodyOpen { // HEAD requests can't have bodies return nil, nil, StreamError{rp.stream.id, ErrCodeProtocol} } var tlsState *tls.ConnectionState // nil if not scheme https if rp.scheme == "https" { tlsState = sc.tlsState } authority := rp.authority if authority == "" { authority = rp.header.Get("Host") } needsContinue := rp.header.Get("Expect") == "100-continue" if needsContinue { rp.header.Del("Expect") } // Merge Cookie headers into one "; "-delimited value. if cookies := rp.header["Cookie"]; len(cookies) > 1 { rp.header.Set("Cookie", strings.Join(cookies, "; ")) } // Setup Trailers var trailer http.Header for _, v := range rp.header["Trailer"] { for _, key := range strings.Split(v, ",") { key = http.CanonicalHeaderKey(strings.TrimSpace(key)) switch key { case "Transfer-Encoding", "Trailer", "Content-Length": // Bogus. (copy of http1 rules) // Ignore. default: if trailer == nil { trailer = make(http.Header) } trailer[key] = nil } } } delete(rp.header, "Trailer") body := &requestBody{ conn: sc, stream: rp.stream, needsContinue: needsContinue, } var url_ *url.URL var requestURI string if isConnect { url_ = &url.URL{Host: rp.authority} requestURI = rp.authority // mimic HTTP/1 server behavior } else { var err error url_, err = url.ParseRequestURI(rp.path) if err != nil { return nil, nil, StreamError{rp.stream.id, ErrCodeProtocol} } requestURI = rp.path } req := &http.Request{ Method: rp.method, URL: url_, RemoteAddr: sc.remoteAddrStr, Header: rp.header, RequestURI: requestURI, Proto: "HTTP/2.0", ProtoMajor: 2, ProtoMinor: 0, TLS: tlsState, Host: authority, Body: body, Trailer: trailer, } if bodyOpen { body.pipe = &pipe{ b: &fixedBuffer{buf: make([]byte, initialWindowSize)}, // TODO: garbage } if vv, ok := rp.header["Content-Length"]; ok { req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64) } else { req.ContentLength = -1 } } rws := responseWriterStatePool.Get().(*responseWriterState) bwSave := rws.bw *rws = responseWriterState{} // zero all the fields rws.conn = sc rws.bw = bwSave rws.bw.Reset(chunkWriter{rws}) rws.stream = rp.stream rws.req = req rws.body = body rw := &responseWriter{rws: rws} return rw, req, nil } // Run on its own goroutine. func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) { didPanic := true defer func() { if didPanic { e := recover() // Same as net/http: const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] sc.writeFrameFromHandler(frameWriteMsg{ write: handlerPanicRST{rw.rws.stream.id}, stream: rw.rws.stream, }) sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf) return } rw.handlerDone() }() handler(rw, req) didPanic = false } func handleHeaderListTooLong(w http.ResponseWriter, r *http.Request) { // 10.5.1 Limits on Header Block Size: // .. "A server that receives a larger header block than it is // willing to handle can send an HTTP 431 (Request Header Fields Too // Large) status code" const statusRequestHeaderFieldsTooLarge = 431 // only in Go 1.6+ w.WriteHeader(statusRequestHeaderFieldsTooLarge) io.WriteString(w, "

    HTTP Error 431

    Request Header Field(s) Too Large

    ") } // called from handler goroutines. // h may be nil. func (sc *serverConn) writeHeaders(st *stream, headerData *writeResHeaders) error { sc.serveG.checkNotOn() // NOT on var errc chan error if headerData.h != nil { // If there's a header map (which we don't own), so we have to block on // waiting for this frame to be written, so an http.Flush mid-handler // writes out the correct value of keys, before a handler later potentially // mutates it. errc = errChanPool.Get().(chan error) } if err := sc.writeFrameFromHandler(frameWriteMsg{ write: headerData, stream: st, done: errc, }); err != nil { return err } if errc != nil { select { case err := <-errc: errChanPool.Put(errc) return err case <-sc.doneServing: return errClientDisconnected case <-st.cw: return errStreamClosed } } return nil } // called from handler goroutines. func (sc *serverConn) write100ContinueHeaders(st *stream) { sc.writeFrameFromHandler(frameWriteMsg{ write: write100ContinueHeadersFrame{st.id}, stream: st, }) } // A bodyReadMsg tells the server loop that the http.Handler read n // bytes of the DATA from the client on the given stream. type bodyReadMsg struct { st *stream n int } // called from handler goroutines. // Notes that the handler for the given stream ID read n bytes of its body // and schedules flow control tokens to be sent. func (sc *serverConn) noteBodyReadFromHandler(st *stream, n int) { sc.serveG.checkNotOn() // NOT on select { case sc.bodyReadCh <- bodyReadMsg{st, n}: case <-sc.doneServing: } } func (sc *serverConn) noteBodyRead(st *stream, n int) { sc.serveG.check() sc.sendWindowUpdate(nil, n) // conn-level if st.state != stateHalfClosedRemote && st.state != stateClosed { // Don't send this WINDOW_UPDATE if the stream is closed // remotely. sc.sendWindowUpdate(st, n) } } // st may be nil for conn-level func (sc *serverConn) sendWindowUpdate(st *stream, n int) { sc.serveG.check() // "The legal range for the increment to the flow control // window is 1 to 2^31-1 (2,147,483,647) octets." // A Go Read call on 64-bit machines could in theory read // a larger Read than this. Very unlikely, but we handle it here // rather than elsewhere for now. const maxUint31 = 1<<31 - 1 for n >= maxUint31 { sc.sendWindowUpdate32(st, maxUint31) n -= maxUint31 } sc.sendWindowUpdate32(st, int32(n)) } // st may be nil for conn-level func (sc *serverConn) sendWindowUpdate32(st *stream, n int32) { sc.serveG.check() if n == 0 { return } if n < 0 { panic("negative update") } var streamID uint32 if st != nil { streamID = st.id } sc.writeFrame(frameWriteMsg{ write: writeWindowUpdate{streamID: streamID, n: uint32(n)}, stream: st, }) var ok bool if st == nil { ok = sc.inflow.add(n) } else { ok = st.inflow.add(n) } if !ok { panic("internal error; sent too many window updates without decrements?") } } type requestBody struct { stream *stream conn *serverConn closed bool pipe *pipe // non-nil if we have a HTTP entity message body needsContinue bool // need to send a 100-continue } func (b *requestBody) Close() error { if b.pipe != nil { b.pipe.CloseWithError(errClosedBody) } b.closed = true return nil } func (b *requestBody) Read(p []byte) (n int, err error) { if b.needsContinue { b.needsContinue = false b.conn.write100ContinueHeaders(b.stream) } if b.pipe == nil { return 0, io.EOF } n, err = b.pipe.Read(p) if n > 0 { b.conn.noteBodyReadFromHandler(b.stream, n) } return } // responseWriter is the http.ResponseWriter implementation. It's // intentionally small (1 pointer wide) to minimize garbage. The // responseWriterState pointer inside is zeroed at the end of a // request (in handlerDone) and calls on the responseWriter thereafter // simply crash (caller's mistake), but the much larger responseWriterState // and buffers are reused between multiple requests. type responseWriter struct { rws *responseWriterState } // Optional http.ResponseWriter interfaces implemented. var ( _ http.CloseNotifier = (*responseWriter)(nil) _ http.Flusher = (*responseWriter)(nil) _ stringWriter = (*responseWriter)(nil) ) type responseWriterState struct { // immutable within a request: stream *stream req *http.Request body *requestBody // to close at end of request, if DATA frames didn't conn *serverConn // TODO: adjust buffer writing sizes based on server config, frame size updates from peer, etc bw *bufio.Writer // writing to a chunkWriter{this *responseWriterState} // mutated by http.Handler goroutine: handlerHeader http.Header // nil until called snapHeader http.Header // snapshot of handlerHeader at WriteHeader time trailers []string // set in writeChunk status int // status code passed to WriteHeader wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet. sentHeader bool // have we sent the header frame? handlerDone bool // handler has finished sentContentLen int64 // non-zero if handler set a Content-Length header wroteBytes int64 closeNotifierMu sync.Mutex // guards closeNotifierCh closeNotifierCh chan bool // nil until first used } type chunkWriter struct{ rws *responseWriterState } func (cw chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) } func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) != 0 } // declareTrailer is called for each Trailer header when the // response header is written. It notes that a header will need to be // written in the trailers at the end of the response. func (rws *responseWriterState) declareTrailer(k string) { k = http.CanonicalHeaderKey(k) switch k { case "Transfer-Encoding", "Content-Length", "Trailer": // Forbidden by RFC 2616 14.40. return } rws.trailers = append(rws.trailers, k) } // writeChunk writes chunks from the bufio.Writer. But because // bufio.Writer may bypass its chunking, sometimes p may be // arbitrarily large. // // writeChunk is also responsible (on the first chunk) for sending the // HEADER response. func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { if !rws.wroteHeader { rws.writeHeader(200) } isHeadResp := rws.req.Method == "HEAD" if !rws.sentHeader { rws.sentHeader = true var ctype, clen string if clen = rws.snapHeader.Get("Content-Length"); clen != "" { rws.snapHeader.Del("Content-Length") clen64, err := strconv.ParseInt(clen, 10, 64) if err == nil && clen64 >= 0 { rws.sentContentLen = clen64 } else { clen = "" } } if clen == "" && rws.handlerDone && bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) { clen = strconv.Itoa(len(p)) } _, hasContentType := rws.snapHeader["Content-Type"] if !hasContentType && bodyAllowedForStatus(rws.status) { ctype = http.DetectContentType(p) } var date string if _, ok := rws.snapHeader["Date"]; !ok { // TODO(bradfitz): be faster here, like net/http? measure. date = time.Now().UTC().Format(http.TimeFormat) } for _, v := range rws.snapHeader["Trailer"] { foreachHeaderElement(v, rws.declareTrailer) } endStream := (rws.handlerDone && !rws.hasTrailers() && len(p) == 0) || isHeadResp err = rws.conn.writeHeaders(rws.stream, &writeResHeaders{ streamID: rws.stream.id, httpResCode: rws.status, h: rws.snapHeader, endStream: endStream, contentType: ctype, contentLength: clen, date: date, }) if err != nil { return 0, err } if endStream { return 0, nil } } if isHeadResp { return len(p), nil } if len(p) == 0 && !rws.handlerDone { return 0, nil } endStream := rws.handlerDone && !rws.hasTrailers() if len(p) > 0 || endStream { // only send a 0 byte DATA frame if we're ending the stream. if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil { return 0, err } } if rws.handlerDone && rws.hasTrailers() { err = rws.conn.writeHeaders(rws.stream, &writeResHeaders{ streamID: rws.stream.id, h: rws.handlerHeader, trailers: rws.trailers, endStream: true, }) return len(p), err } return len(p), nil } func (w *responseWriter) Flush() { rws := w.rws if rws == nil { panic("Header called after Handler finished") } if rws.bw.Buffered() > 0 { if err := rws.bw.Flush(); err != nil { // Ignore the error. The frame writer already knows. return } } else { // The bufio.Writer won't call chunkWriter.Write // (writeChunk with zero bytes, so we have to do it // ourselves to force the HTTP response header and/or // final DATA frame (with END_STREAM) to be sent. rws.writeChunk(nil) } } func (w *responseWriter) CloseNotify() <-chan bool { rws := w.rws if rws == nil { panic("CloseNotify called after Handler finished") } rws.closeNotifierMu.Lock() ch := rws.closeNotifierCh if ch == nil { ch = make(chan bool, 1) rws.closeNotifierCh = ch go func() { rws.stream.cw.Wait() // wait for close ch <- true }() } rws.closeNotifierMu.Unlock() return ch } func (w *responseWriter) Header() http.Header { rws := w.rws if rws == nil { panic("Header called after Handler finished") } if rws.handlerHeader == nil { rws.handlerHeader = make(http.Header) } return rws.handlerHeader } func (w *responseWriter) WriteHeader(code int) { rws := w.rws if rws == nil { panic("WriteHeader called after Handler finished") } rws.writeHeader(code) } func (rws *responseWriterState) writeHeader(code int) { if !rws.wroteHeader { rws.wroteHeader = true rws.status = code if len(rws.handlerHeader) > 0 { rws.snapHeader = cloneHeader(rws.handlerHeader) } } } func cloneHeader(h http.Header) http.Header { h2 := make(http.Header, len(h)) for k, vv := range h { vv2 := make([]string, len(vv)) copy(vv2, vv) h2[k] = vv2 } return h2 } // The Life Of A Write is like this: // // * Handler calls w.Write or w.WriteString -> // * -> rws.bw (*bufio.Writer) -> // * (Handler migth call Flush) // * -> chunkWriter{rws} // * -> responseWriterState.writeChunk(p []byte) // * -> responseWriterState.writeChunk (most of the magic; see comment there) func (w *responseWriter) Write(p []byte) (n int, err error) { return w.write(len(p), p, "") } func (w *responseWriter) WriteString(s string) (n int, err error) { return w.write(len(s), nil, s) } // either dataB or dataS is non-zero. func (w *responseWriter) write(lenData int, dataB []byte, dataS string) (n int, err error) { rws := w.rws if rws == nil { panic("Write called after Handler finished") } if !rws.wroteHeader { w.WriteHeader(200) } if !bodyAllowedForStatus(rws.status) { return 0, http.ErrBodyNotAllowed } rws.wroteBytes += int64(len(dataB)) + int64(len(dataS)) // only one can be set if rws.sentContentLen != 0 && rws.wroteBytes > rws.sentContentLen { // TODO: send a RST_STREAM return 0, errors.New("http2: handler wrote more than declared Content-Length") } if dataB != nil { return rws.bw.Write(dataB) } else { return rws.bw.WriteString(dataS) } } func (w *responseWriter) handlerDone() { rws := w.rws rws.handlerDone = true w.Flush() w.rws = nil responseWriterStatePool.Put(rws) } // foreachHeaderElement splits v according to the "#rule" construction // in RFC 2616 section 2.1 and calls fn for each non-empty element. func foreachHeaderElement(v string, fn func(string)) { v = textproto.TrimString(v) if v == "" { return } if !strings.Contains(v, ",") { fn(v) return } for _, f := range strings.Split(v, ",") { if f = textproto.TrimString(f); f != "" { fn(f) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/server_test.go000066400000000000000000002360401264464372400244020ustar00rootroot00000000000000// Copyright 2014 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 http2 import ( "bytes" "crypto/tls" "errors" "flag" "fmt" "io" "io/ioutil" "log" "net" "net/http" "net/http/httptest" "os" "os/exec" "reflect" "runtime" "strconv" "strings" "sync" "sync/atomic" "testing" "time" "golang.org/x/net/http2/hpack" ) var stderrVerbose = flag.Bool("stderr_verbose", false, "Mirror verbosity to stderr, unbuffered") func stderrv() io.Writer { if *stderrVerbose { return os.Stderr } return ioutil.Discard } type serverTester struct { cc net.Conn // client conn t testing.TB ts *httptest.Server fr *Framer logBuf *bytes.Buffer logFilter []string // substrings to filter out scMu sync.Mutex // guards sc sc *serverConn hpackDec *hpack.Decoder decodedHeaders [][2]string // writing headers: headerBuf bytes.Buffer hpackEnc *hpack.Encoder // reading frames: frc chan Frame frErrc chan error readTimer *time.Timer } func init() { testHookOnPanicMu = new(sync.Mutex) } func resetHooks() { testHookOnPanicMu.Lock() testHookOnPanic = nil testHookOnPanicMu.Unlock() } type serverTesterOpt string var optOnlyServer = serverTesterOpt("only_server") func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}) *serverTester { resetHooks() logBuf := new(bytes.Buffer) ts := httptest.NewUnstartedServer(handler) tlsConfig := &tls.Config{ InsecureSkipVerify: true, // The h2-14 is temporary, until curl is updated. (as used by unit tests // in Docker) NextProtos: []string{NextProtoTLS, "h2-14"}, } onlyServer := false for _, opt := range opts { switch v := opt.(type) { case func(*tls.Config): v(tlsConfig) case func(*httptest.Server): v(ts) case serverTesterOpt: onlyServer = (v == optOnlyServer) default: t.Fatalf("unknown newServerTester option type %T", v) } } ConfigureServer(ts.Config, &Server{}) st := &serverTester{ t: t, ts: ts, logBuf: logBuf, frc: make(chan Frame, 1), frErrc: make(chan error, 1), } st.hpackEnc = hpack.NewEncoder(&st.headerBuf) st.hpackDec = hpack.NewDecoder(initialHeaderTableSize, st.onHeaderField) ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config ts.Config.ErrorLog = log.New(io.MultiWriter(stderrv(), twriter{t: t, st: st}, logBuf), "", log.LstdFlags) ts.StartTLS() if VerboseLogs { t.Logf("Running test server at: %s", ts.URL) } testHookGetServerConn = func(v *serverConn) { st.scMu.Lock() defer st.scMu.Unlock() st.sc = v st.sc.testHookCh = make(chan func(int)) } log.SetOutput(io.MultiWriter(stderrv(), twriter{t: t, st: st})) if !onlyServer { cc, err := tls.Dial("tcp", ts.Listener.Addr().String(), tlsConfig) if err != nil { t.Fatal(err) } st.cc = cc st.fr = NewFramer(cc, cc) } return st } func (st *serverTester) closeConn() { st.scMu.Lock() defer st.scMu.Unlock() st.sc.conn.Close() } func (st *serverTester) addLogFilter(phrase string) { st.logFilter = append(st.logFilter, phrase) } func (st *serverTester) stream(id uint32) *stream { ch := make(chan *stream, 1) st.sc.testHookCh <- func(int) { ch <- st.sc.streams[id] } return <-ch } func (st *serverTester) streamState(id uint32) streamState { ch := make(chan streamState, 1) st.sc.testHookCh <- func(int) { state, _ := st.sc.state(id) ch <- state } return <-ch } // loopNum reports how many times this conn's select loop has gone around. func (st *serverTester) loopNum() int { lastc := make(chan int, 1) st.sc.testHookCh <- func(loopNum int) { lastc <- loopNum } return <-lastc } // awaitIdle heuristically awaits for the server conn's select loop to be idle. // The heuristic is that the server connection's serve loop must schedule // 50 times in a row without any channel sends or receives occuring. func (st *serverTester) awaitIdle() { remain := 50 last := st.loopNum() for remain > 0 { n := st.loopNum() if n == last+1 { remain-- } else { remain = 50 } last = n } } func (st *serverTester) Close() { st.ts.Close() if st.cc != nil { st.cc.Close() } log.SetOutput(os.Stderr) } // greet initiates the client's HTTP/2 connection into a state where // frames may be sent. func (st *serverTester) greet() { st.writePreface() st.writeInitialSettings() st.wantSettings() st.writeSettingsAck() st.wantSettingsAck() } func (st *serverTester) writePreface() { n, err := st.cc.Write(clientPreface) if err != nil { st.t.Fatalf("Error writing client preface: %v", err) } if n != len(clientPreface) { st.t.Fatalf("Writing client preface, wrote %d bytes; want %d", n, len(clientPreface)) } } func (st *serverTester) writeInitialSettings() { if err := st.fr.WriteSettings(); err != nil { st.t.Fatalf("Error writing initial SETTINGS frame from client to server: %v", err) } } func (st *serverTester) writeSettingsAck() { if err := st.fr.WriteSettingsAck(); err != nil { st.t.Fatalf("Error writing ACK of server's SETTINGS: %v", err) } } func (st *serverTester) writeHeaders(p HeadersFrameParam) { if err := st.fr.WriteHeaders(p); err != nil { st.t.Fatalf("Error writing HEADERS: %v", err) } } func (st *serverTester) encodeHeaderField(k, v string) { err := st.hpackEnc.WriteField(hpack.HeaderField{Name: k, Value: v}) if err != nil { st.t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err) } } // encodeHeaderRaw is the magic-free version of encodeHeader. // It takes 0 or more (k, v) pairs and encodes them. func (st *serverTester) encodeHeaderRaw(headers ...string) []byte { if len(headers)%2 == 1 { panic("odd number of kv args") } st.headerBuf.Reset() for len(headers) > 0 { k, v := headers[0], headers[1] st.encodeHeaderField(k, v) headers = headers[2:] } return st.headerBuf.Bytes() } // encodeHeader encodes headers and returns their HPACK bytes. headers // must contain an even number of key/value pairs. There may be // multiple pairs for keys (e.g. "cookie"). The :method, :path, and // :scheme headers default to GET, / and https. func (st *serverTester) encodeHeader(headers ...string) []byte { if len(headers)%2 == 1 { panic("odd number of kv args") } st.headerBuf.Reset() if len(headers) == 0 { // Fast path, mostly for benchmarks, so test code doesn't pollute // profiles when we're looking to improve server allocations. st.encodeHeaderField(":method", "GET") st.encodeHeaderField(":path", "/") st.encodeHeaderField(":scheme", "https") return st.headerBuf.Bytes() } if len(headers) == 2 && headers[0] == ":method" { // Another fast path for benchmarks. st.encodeHeaderField(":method", headers[1]) st.encodeHeaderField(":path", "/") st.encodeHeaderField(":scheme", "https") return st.headerBuf.Bytes() } pseudoCount := map[string]int{} keys := []string{":method", ":path", ":scheme"} vals := map[string][]string{ ":method": {"GET"}, ":path": {"/"}, ":scheme": {"https"}, } for len(headers) > 0 { k, v := headers[0], headers[1] headers = headers[2:] if _, ok := vals[k]; !ok { keys = append(keys, k) } if strings.HasPrefix(k, ":") { pseudoCount[k]++ if pseudoCount[k] == 1 { vals[k] = []string{v} } else { // Allows testing of invalid headers w/ dup pseudo fields. vals[k] = append(vals[k], v) } } else { vals[k] = append(vals[k], v) } } for _, k := range keys { for _, v := range vals[k] { st.encodeHeaderField(k, v) } } return st.headerBuf.Bytes() } // bodylessReq1 writes a HEADERS frames with StreamID 1 and EndStream and EndHeaders set. func (st *serverTester) bodylessReq1(headers ...string) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(headers...), EndStream: true, EndHeaders: true, }) } func (st *serverTester) writeData(streamID uint32, endStream bool, data []byte) { if err := st.fr.WriteData(streamID, endStream, data); err != nil { st.t.Fatalf("Error writing DATA: %v", err) } } func (st *serverTester) readFrame() (Frame, error) { go func() { fr, err := st.fr.ReadFrame() if err != nil { st.frErrc <- err } else { st.frc <- fr } }() t := st.readTimer if t == nil { t = time.NewTimer(2 * time.Second) st.readTimer = t } t.Reset(2 * time.Second) defer t.Stop() select { case f := <-st.frc: return f, nil case err := <-st.frErrc: return nil, err case <-t.C: return nil, errors.New("timeout waiting for frame") } } func (st *serverTester) wantHeaders() *HeadersFrame { f, err := st.readFrame() if err != nil { st.t.Fatalf("Error while expecting a HEADERS frame: %v", err) } hf, ok := f.(*HeadersFrame) if !ok { st.t.Fatalf("got a %T; want *HeadersFrame", f) } return hf } func (st *serverTester) wantContinuation() *ContinuationFrame { f, err := st.readFrame() if err != nil { st.t.Fatalf("Error while expecting a CONTINUATION frame: %v", err) } cf, ok := f.(*ContinuationFrame) if !ok { st.t.Fatalf("got a %T; want *ContinuationFrame", f) } return cf } func (st *serverTester) wantData() *DataFrame { f, err := st.readFrame() if err != nil { st.t.Fatalf("Error while expecting a DATA frame: %v", err) } df, ok := f.(*DataFrame) if !ok { st.t.Fatalf("got a %T; want *DataFrame", f) } return df } func (st *serverTester) wantSettings() *SettingsFrame { f, err := st.readFrame() if err != nil { st.t.Fatalf("Error while expecting a SETTINGS frame: %v", err) } sf, ok := f.(*SettingsFrame) if !ok { st.t.Fatalf("got a %T; want *SettingsFrame", f) } return sf } func (st *serverTester) wantPing() *PingFrame { f, err := st.readFrame() if err != nil { st.t.Fatalf("Error while expecting a PING frame: %v", err) } pf, ok := f.(*PingFrame) if !ok { st.t.Fatalf("got a %T; want *PingFrame", f) } return pf } func (st *serverTester) wantGoAway() *GoAwayFrame { f, err := st.readFrame() if err != nil { st.t.Fatalf("Error while expecting a GOAWAY frame: %v", err) } gf, ok := f.(*GoAwayFrame) if !ok { st.t.Fatalf("got a %T; want *GoAwayFrame", f) } return gf } func (st *serverTester) wantRSTStream(streamID uint32, errCode ErrCode) { f, err := st.readFrame() if err != nil { st.t.Fatalf("Error while expecting an RSTStream frame: %v", err) } rs, ok := f.(*RSTStreamFrame) if !ok { st.t.Fatalf("got a %T; want *RSTStreamFrame", f) } if rs.FrameHeader.StreamID != streamID { st.t.Fatalf("RSTStream StreamID = %d; want %d", rs.FrameHeader.StreamID, streamID) } if rs.ErrCode != errCode { st.t.Fatalf("RSTStream ErrCode = %d (%s); want %d (%s)", rs.ErrCode, rs.ErrCode, errCode, errCode) } } func (st *serverTester) wantWindowUpdate(streamID, incr uint32) { f, err := st.readFrame() if err != nil { st.t.Fatalf("Error while expecting a WINDOW_UPDATE frame: %v", err) } wu, ok := f.(*WindowUpdateFrame) if !ok { st.t.Fatalf("got a %T; want *WindowUpdateFrame", f) } if wu.FrameHeader.StreamID != streamID { st.t.Fatalf("WindowUpdate StreamID = %d; want %d", wu.FrameHeader.StreamID, streamID) } if wu.Increment != incr { st.t.Fatalf("WindowUpdate increment = %d; want %d", wu.Increment, incr) } } func (st *serverTester) wantSettingsAck() { f, err := st.readFrame() if err != nil { st.t.Fatal(err) } sf, ok := f.(*SettingsFrame) if !ok { st.t.Fatalf("Wanting a settings ACK, received a %T", f) } if !sf.Header().Flags.Has(FlagSettingsAck) { st.t.Fatal("Settings Frame didn't have ACK set") } } func TestServer(t *testing.T) { gotReq := make(chan bool, 1) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Foo", "Bar") gotReq <- true }) defer st.Close() covers("3.5", ` The server connection preface consists of a potentially empty SETTINGS frame ([SETTINGS]) that MUST be the first frame the server sends in the HTTP/2 connection. `) st.writePreface() st.writeInitialSettings() st.wantSettings() st.writeSettingsAck() st.wantSettingsAck() st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(), EndStream: true, // no DATA frames EndHeaders: true, }) select { case <-gotReq: case <-time.After(2 * time.Second): t.Error("timeout waiting for request") } } func TestServer_Request_Get(t *testing.T) { testServerRequest(t, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader("foo-bar", "some-value"), EndStream: true, // no DATA frames EndHeaders: true, }) }, func(r *http.Request) { if r.Method != "GET" { t.Errorf("Method = %q; want GET", r.Method) } if r.URL.Path != "/" { t.Errorf("URL.Path = %q; want /", r.URL.Path) } if r.ContentLength != 0 { t.Errorf("ContentLength = %v; want 0", r.ContentLength) } if r.Close { t.Error("Close = true; want false") } if !strings.Contains(r.RemoteAddr, ":") { t.Errorf("RemoteAddr = %q; want something with a colon", r.RemoteAddr) } if r.Proto != "HTTP/2.0" || r.ProtoMajor != 2 || r.ProtoMinor != 0 { t.Errorf("Proto = %q Major=%v,Minor=%v; want HTTP/2.0", r.Proto, r.ProtoMajor, r.ProtoMinor) } wantHeader := http.Header{ "Foo-Bar": []string{"some-value"}, } if !reflect.DeepEqual(r.Header, wantHeader) { t.Errorf("Header = %#v; want %#v", r.Header, wantHeader) } if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 { t.Errorf("Read = %d, %v; want 0, EOF", n, err) } }) } func TestServer_Request_Get_PathSlashes(t *testing.T) { testServerRequest(t, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(":path", "/%2f/"), EndStream: true, // no DATA frames EndHeaders: true, }) }, func(r *http.Request) { if r.RequestURI != "/%2f/" { t.Errorf("RequestURI = %q; want /%%2f/", r.RequestURI) } if r.URL.Path != "///" { t.Errorf("URL.Path = %q; want ///", r.URL.Path) } }) } // TODO: add a test with EndStream=true on the HEADERS but setting a // Content-Length anyway. Should we just omit it and force it to // zero? func TestServer_Request_Post_NoContentLength_EndStream(t *testing.T) { testServerRequest(t, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(":method", "POST"), EndStream: true, EndHeaders: true, }) }, func(r *http.Request) { if r.Method != "POST" { t.Errorf("Method = %q; want POST", r.Method) } if r.ContentLength != 0 { t.Errorf("ContentLength = %v; want 0", r.ContentLength) } if n, err := r.Body.Read([]byte(" ")); err != io.EOF || n != 0 { t.Errorf("Read = %d, %v; want 0, EOF", n, err) } }) } func TestServer_Request_Post_Body_ImmediateEOF(t *testing.T) { testBodyContents(t, -1, "", func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(":method", "POST"), EndStream: false, // to say DATA frames are coming EndHeaders: true, }) st.writeData(1, true, nil) // just kidding. empty body. }) } func TestServer_Request_Post_Body_OneData(t *testing.T) { const content = "Some content" testBodyContents(t, -1, content, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(":method", "POST"), EndStream: false, // to say DATA frames are coming EndHeaders: true, }) st.writeData(1, true, []byte(content)) }) } func TestServer_Request_Post_Body_TwoData(t *testing.T) { const content = "Some content" testBodyContents(t, -1, content, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(":method", "POST"), EndStream: false, // to say DATA frames are coming EndHeaders: true, }) st.writeData(1, false, []byte(content[:5])) st.writeData(1, true, []byte(content[5:])) }) } func TestServer_Request_Post_Body_ContentLength_Correct(t *testing.T) { const content = "Some content" testBodyContents(t, int64(len(content)), content, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader( ":method", "POST", "content-length", strconv.Itoa(len(content)), ), EndStream: false, // to say DATA frames are coming EndHeaders: true, }) st.writeData(1, true, []byte(content)) }) } func TestServer_Request_Post_Body_ContentLength_TooLarge(t *testing.T) { testBodyContentsFail(t, 3, "request declared a Content-Length of 3 but only wrote 2 bytes", func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader( ":method", "POST", "content-length", "3", ), EndStream: false, // to say DATA frames are coming EndHeaders: true, }) st.writeData(1, true, []byte("12")) }) } func TestServer_Request_Post_Body_ContentLength_TooSmall(t *testing.T) { testBodyContentsFail(t, 4, "sender tried to send more than declared Content-Length of 4 bytes", func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader( ":method", "POST", "content-length", "4", ), EndStream: false, // to say DATA frames are coming EndHeaders: true, }) st.writeData(1, true, []byte("12345")) }) } func testBodyContents(t *testing.T, wantContentLength int64, wantBody string, write func(st *serverTester)) { testServerRequest(t, write, func(r *http.Request) { if r.Method != "POST" { t.Errorf("Method = %q; want POST", r.Method) } if r.ContentLength != wantContentLength { t.Errorf("ContentLength = %v; want %d", r.ContentLength, wantContentLength) } all, err := ioutil.ReadAll(r.Body) if err != nil { t.Fatal(err) } if string(all) != wantBody { t.Errorf("Read = %q; want %q", all, wantBody) } if err := r.Body.Close(); err != nil { t.Fatalf("Close: %v", err) } }) } func testBodyContentsFail(t *testing.T, wantContentLength int64, wantReadError string, write func(st *serverTester)) { testServerRequest(t, write, func(r *http.Request) { if r.Method != "POST" { t.Errorf("Method = %q; want POST", r.Method) } if r.ContentLength != wantContentLength { t.Errorf("ContentLength = %v; want %d", r.ContentLength, wantContentLength) } all, err := ioutil.ReadAll(r.Body) if err == nil { t.Fatalf("expected an error (%q) reading from the body. Successfully read %q instead.", wantReadError, all) } if !strings.Contains(err.Error(), wantReadError) { t.Fatalf("Body.Read = %v; want substring %q", err, wantReadError) } if err := r.Body.Close(); err != nil { t.Fatalf("Close: %v", err) } }) } // Using a Host header, instead of :authority func TestServer_Request_Get_Host(t *testing.T) { const host = "example.com" testServerRequest(t, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader("host", host), EndStream: true, EndHeaders: true, }) }, func(r *http.Request) { if r.Host != host { t.Errorf("Host = %q; want %q", r.Host, host) } }) } // Using an :authority pseudo-header, instead of Host func TestServer_Request_Get_Authority(t *testing.T) { const host = "example.com" testServerRequest(t, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(":authority", host), EndStream: true, EndHeaders: true, }) }, func(r *http.Request) { if r.Host != host { t.Errorf("Host = %q; want %q", r.Host, host) } }) } func TestServer_Request_WithContinuation(t *testing.T) { wantHeader := http.Header{ "Foo-One": []string{"value-one"}, "Foo-Two": []string{"value-two"}, "Foo-Three": []string{"value-three"}, } testServerRequest(t, func(st *serverTester) { fullHeaders := st.encodeHeader( "foo-one", "value-one", "foo-two", "value-two", "foo-three", "value-three", ) remain := fullHeaders chunks := 0 for len(remain) > 0 { const maxChunkSize = 5 chunk := remain if len(chunk) > maxChunkSize { chunk = chunk[:maxChunkSize] } remain = remain[len(chunk):] if chunks == 0 { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: chunk, EndStream: true, // no DATA frames EndHeaders: false, // we'll have continuation frames }) } else { err := st.fr.WriteContinuation(1, len(remain) == 0, chunk) if err != nil { t.Fatal(err) } } chunks++ } if chunks < 2 { t.Fatal("too few chunks") } }, func(r *http.Request) { if !reflect.DeepEqual(r.Header, wantHeader) { t.Errorf("Header = %#v; want %#v", r.Header, wantHeader) } }) } // Concatenated cookie headers. ("8.1.2.5 Compressing the Cookie Header Field") func TestServer_Request_CookieConcat(t *testing.T) { const host = "example.com" testServerRequest(t, func(st *serverTester) { st.bodylessReq1( ":authority", host, "cookie", "a=b", "cookie", "c=d", "cookie", "e=f", ) }, func(r *http.Request) { const want = "a=b; c=d; e=f" if got := r.Header.Get("Cookie"); got != want { t.Errorf("Cookie = %q; want %q", got, want) } }) } func TestServer_Request_Reject_CapitalHeader(t *testing.T) { testRejectRequest(t, func(st *serverTester) { st.bodylessReq1("UPPER", "v") }) } func TestServer_Request_Reject_Pseudo_Missing_method(t *testing.T) { testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":method", "") }) } func TestServer_Request_Reject_Pseudo_ExactlyOne(t *testing.T) { // 8.1.2.3 Request Pseudo-Header Fields // "All HTTP/2 requests MUST include exactly one valid value" ... testRejectRequest(t, func(st *serverTester) { st.addLogFilter("duplicate pseudo-header") st.bodylessReq1(":method", "GET", ":method", "POST") }) } func TestServer_Request_Reject_Pseudo_AfterRegular(t *testing.T) { // 8.1.2.3 Request Pseudo-Header Fields // "All pseudo-header fields MUST appear in the header block // before regular header fields. Any request or response that // contains a pseudo-header field that appears in a header // block after a regular header field MUST be treated as // malformed (Section 8.1.2.6)." testRejectRequest(t, func(st *serverTester) { st.addLogFilter("pseudo-header after regular header") var buf bytes.Buffer enc := hpack.NewEncoder(&buf) enc.WriteField(hpack.HeaderField{Name: ":method", Value: "GET"}) enc.WriteField(hpack.HeaderField{Name: "regular", Value: "foobar"}) enc.WriteField(hpack.HeaderField{Name: ":path", Value: "/"}) enc.WriteField(hpack.HeaderField{Name: ":scheme", Value: "https"}) st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: buf.Bytes(), EndStream: true, EndHeaders: true, }) }) } func TestServer_Request_Reject_Pseudo_Missing_path(t *testing.T) { testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":path", "") }) } func TestServer_Request_Reject_Pseudo_Missing_scheme(t *testing.T) { testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":scheme", "") }) } func TestServer_Request_Reject_Pseudo_scheme_invalid(t *testing.T) { testRejectRequest(t, func(st *serverTester) { st.bodylessReq1(":scheme", "bogus") }) } func TestServer_Request_Reject_Pseudo_Unknown(t *testing.T) { testRejectRequest(t, func(st *serverTester) { st.addLogFilter(`invalid pseudo-header ":unknown_thing"`) st.bodylessReq1(":unknown_thing", "") }) } func testRejectRequest(t *testing.T, send func(*serverTester)) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { t.Fatal("server request made it to handler; should've been rejected") }) defer st.Close() st.greet() send(st) st.wantRSTStream(1, ErrCodeProtocol) } func TestServer_Request_Connect(t *testing.T) { testServerRequest(t, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeaderRaw( ":method", "CONNECT", ":authority", "example.com:123", ), EndStream: true, EndHeaders: true, }) }, func(r *http.Request) { if g, w := r.Method, "CONNECT"; g != w { t.Errorf("Method = %q; want %q", g, w) } if g, w := r.RequestURI, "example.com:123"; g != w { t.Errorf("RequestURI = %q; want %q", g, w) } if g, w := r.URL.Host, "example.com:123"; g != w { t.Errorf("URL.Host = %q; want %q", g, w) } }) } func TestServer_Request_Connect_InvalidPath(t *testing.T) { testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeaderRaw( ":method", "CONNECT", ":authority", "example.com:123", ":path", "/bogus", ), EndStream: true, EndHeaders: true, }) }) } func TestServer_Request_Connect_InvalidScheme(t *testing.T) { testServerRejectsStream(t, ErrCodeProtocol, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeaderRaw( ":method", "CONNECT", ":authority", "example.com:123", ":scheme", "https", ), EndStream: true, EndHeaders: true, }) }) } func TestServer_Ping(t *testing.T) { st := newServerTester(t, nil) defer st.Close() st.greet() // Server should ignore this one, since it has ACK set. ackPingData := [8]byte{1, 2, 4, 8, 16, 32, 64, 128} if err := st.fr.WritePing(true, ackPingData); err != nil { t.Fatal(err) } // But the server should reply to this one, since ACK is false. pingData := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} if err := st.fr.WritePing(false, pingData); err != nil { t.Fatal(err) } pf := st.wantPing() if !pf.Flags.Has(FlagPingAck) { t.Error("response ping doesn't have ACK set") } if pf.Data != pingData { t.Errorf("response ping has data %q; want %q", pf.Data, pingData) } } func TestServer_RejectsLargeFrames(t *testing.T) { st := newServerTester(t, nil) defer st.Close() st.greet() // Write too large of a frame (too large by one byte) // We ignore the return value because it's expected that the server // will only read the first 9 bytes (the headre) and then disconnect. st.fr.WriteRawFrame(0xff, 0, 0, make([]byte, defaultMaxReadFrameSize+1)) gf := st.wantGoAway() if gf.ErrCode != ErrCodeFrameSize { t.Errorf("GOAWAY err = %v; want %v", gf.ErrCode, ErrCodeFrameSize) } if st.logBuf.Len() != 0 { // Previously we spun here for a bit until the GOAWAY disconnect // timer fired, logging while we fired. t.Errorf("unexpected server output: %.500s\n", st.logBuf.Bytes()) } } func TestServer_Handler_Sends_WindowUpdate(t *testing.T) { puppet := newHandlerPuppet() st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { puppet.act(w, r) }) defer st.Close() defer puppet.done() st.greet() st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(":method", "POST"), EndStream: false, // data coming EndHeaders: true, }) st.writeData(1, false, []byte("abcdef")) puppet.do(readBodyHandler(t, "abc")) st.wantWindowUpdate(0, 3) st.wantWindowUpdate(1, 3) puppet.do(readBodyHandler(t, "def")) st.wantWindowUpdate(0, 3) st.wantWindowUpdate(1, 3) st.writeData(1, true, []byte("ghijkl")) // END_STREAM here puppet.do(readBodyHandler(t, "ghi")) puppet.do(readBodyHandler(t, "jkl")) st.wantWindowUpdate(0, 3) st.wantWindowUpdate(0, 3) // no more stream-level, since END_STREAM } func TestServer_Send_GoAway_After_Bogus_WindowUpdate(t *testing.T) { st := newServerTester(t, nil) defer st.Close() st.greet() if err := st.fr.WriteWindowUpdate(0, 1<<31-1); err != nil { t.Fatal(err) } gf := st.wantGoAway() if gf.ErrCode != ErrCodeFlowControl { t.Errorf("GOAWAY err = %v; want %v", gf.ErrCode, ErrCodeFlowControl) } if gf.LastStreamID != 0 { t.Errorf("GOAWAY last stream ID = %v; want %v", gf.LastStreamID, 0) } } func TestServer_Send_RstStream_After_Bogus_WindowUpdate(t *testing.T) { inHandler := make(chan bool) blockHandler := make(chan bool) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { inHandler <- true <-blockHandler }) defer st.Close() defer close(blockHandler) st.greet() st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(":method", "POST"), EndStream: false, // keep it open EndHeaders: true, }) <-inHandler // Send a bogus window update: if err := st.fr.WriteWindowUpdate(1, 1<<31-1); err != nil { t.Fatal(err) } st.wantRSTStream(1, ErrCodeFlowControl) } // testServerPostUnblock sends a hanging POST with unsent data to handler, // then runs fn once in the handler, and verifies that the error returned from // handler is acceptable. It fails if takes over 5 seconds for handler to exit. func testServerPostUnblock(t *testing.T, handler func(http.ResponseWriter, *http.Request) error, fn func(*serverTester), checkErr func(error), otherHeaders ...string) { inHandler := make(chan bool) errc := make(chan error, 1) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { inHandler <- true errc <- handler(w, r) }) st.greet() st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(append([]string{":method", "POST"}, otherHeaders...)...), EndStream: false, // keep it open EndHeaders: true, }) <-inHandler fn(st) select { case err := <-errc: if checkErr != nil { checkErr(err) } case <-time.After(5 * time.Second): t.Fatal("timeout waiting for Handler to return") } st.Close() } func TestServer_RSTStream_Unblocks_Read(t *testing.T) { testServerPostUnblock(t, func(w http.ResponseWriter, r *http.Request) (err error) { _, err = r.Body.Read(make([]byte, 1)) return }, func(st *serverTester) { if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil { t.Fatal(err) } }, func(err error) { if err == nil { t.Error("unexpected nil error from Request.Body.Read") } }, ) } func TestServer_RSTStream_Unblocks_Header_Write(t *testing.T) { // Run this test a bunch, because it doesn't always // deadlock. But with a bunch, it did. n := 50 if testing.Short() { n = 5 } for i := 0; i < n; i++ { testServer_RSTStream_Unblocks_Header_Write(t) } } func testServer_RSTStream_Unblocks_Header_Write(t *testing.T) { inHandler := make(chan bool, 1) unblockHandler := make(chan bool, 1) headerWritten := make(chan bool, 1) wroteRST := make(chan bool, 1) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { inHandler <- true <-wroteRST w.Header().Set("foo", "bar") w.WriteHeader(200) w.(http.Flusher).Flush() headerWritten <- true <-unblockHandler }) defer st.Close() st.greet() st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(":method", "POST"), EndStream: false, // keep it open EndHeaders: true, }) <-inHandler if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil { t.Fatal(err) } wroteRST <- true st.awaitIdle() select { case <-headerWritten: case <-time.After(2 * time.Second): t.Error("timeout waiting for header write") } unblockHandler <- true } func TestServer_DeadConn_Unblocks_Read(t *testing.T) { testServerPostUnblock(t, func(w http.ResponseWriter, r *http.Request) (err error) { _, err = r.Body.Read(make([]byte, 1)) return }, func(st *serverTester) { st.cc.Close() }, func(err error) { if err == nil { t.Error("unexpected nil error from Request.Body.Read") } }, ) } var blockUntilClosed = func(w http.ResponseWriter, r *http.Request) error { <-w.(http.CloseNotifier).CloseNotify() return nil } func TestServer_CloseNotify_After_RSTStream(t *testing.T) { testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) { if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil { t.Fatal(err) } }, nil) } func TestServer_CloseNotify_After_ConnClose(t *testing.T) { testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) { st.cc.Close() }, nil) } // that CloseNotify unblocks after a stream error due to the client's // problem that's unrelated to them explicitly canceling it (which is // TestServer_CloseNotify_After_RSTStream above) func TestServer_CloseNotify_After_StreamError(t *testing.T) { testServerPostUnblock(t, blockUntilClosed, func(st *serverTester) { // data longer than declared Content-Length => stream error st.writeData(1, true, []byte("1234")) }, nil, "content-length", "3") } func TestServer_StateTransitions(t *testing.T) { var st *serverTester inHandler := make(chan bool) writeData := make(chan bool) leaveHandler := make(chan bool) st = newServerTester(t, func(w http.ResponseWriter, r *http.Request) { inHandler <- true if st.stream(1) == nil { t.Errorf("nil stream 1 in handler") } if got, want := st.streamState(1), stateOpen; got != want { t.Errorf("in handler, state is %v; want %v", got, want) } writeData <- true if n, err := r.Body.Read(make([]byte, 1)); n != 0 || err != io.EOF { t.Errorf("body read = %d, %v; want 0, EOF", n, err) } if got, want := st.streamState(1), stateHalfClosedRemote; got != want { t.Errorf("in handler, state is %v; want %v", got, want) } <-leaveHandler }) st.greet() if st.stream(1) != nil { t.Fatal("stream 1 should be empty") } if got := st.streamState(1); got != stateIdle { t.Fatalf("stream 1 should be idle; got %v", got) } st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(":method", "POST"), EndStream: false, // keep it open EndHeaders: true, }) <-inHandler <-writeData st.writeData(1, true, nil) leaveHandler <- true hf := st.wantHeaders() if !hf.StreamEnded() { t.Fatal("expected END_STREAM flag") } if got, want := st.streamState(1), stateClosed; got != want { t.Errorf("at end, state is %v; want %v", got, want) } if st.stream(1) != nil { t.Fatal("at end, stream 1 should be gone") } } // test HEADERS w/o EndHeaders + another HEADERS (should get rejected) func TestServer_Rejects_HeadersNoEnd_Then_Headers(t *testing.T) { testServerRejectsConn(t, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(), EndStream: true, EndHeaders: false, }) st.writeHeaders(HeadersFrameParam{ // Not a continuation. StreamID: 3, // different stream. BlockFragment: st.encodeHeader(), EndStream: true, EndHeaders: true, }) }) } // test HEADERS w/o EndHeaders + PING (should get rejected) func TestServer_Rejects_HeadersNoEnd_Then_Ping(t *testing.T) { testServerRejectsConn(t, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(), EndStream: true, EndHeaders: false, }) if err := st.fr.WritePing(false, [8]byte{}); err != nil { t.Fatal(err) } }) } // test HEADERS w/ EndHeaders + a continuation HEADERS (should get rejected) func TestServer_Rejects_HeadersEnd_Then_Continuation(t *testing.T) { testServerRejectsConn(t, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(), EndStream: true, EndHeaders: true, }) st.wantHeaders() if err := st.fr.WriteContinuation(1, true, encodeHeaderNoImplicit(t, "foo", "bar")); err != nil { t.Fatal(err) } }) } // test HEADERS w/o EndHeaders + a continuation HEADERS on wrong stream ID func TestServer_Rejects_HeadersNoEnd_Then_ContinuationWrongStream(t *testing.T) { testServerRejectsConn(t, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(), EndStream: true, EndHeaders: false, }) if err := st.fr.WriteContinuation(3, true, encodeHeaderNoImplicit(t, "foo", "bar")); err != nil { t.Fatal(err) } }) } // No HEADERS on stream 0. func TestServer_Rejects_Headers0(t *testing.T) { testServerRejectsConn(t, func(st *serverTester) { st.fr.AllowIllegalWrites = true st.writeHeaders(HeadersFrameParam{ StreamID: 0, BlockFragment: st.encodeHeader(), EndStream: true, EndHeaders: true, }) }) } // No CONTINUATION on stream 0. func TestServer_Rejects_Continuation0(t *testing.T) { testServerRejectsConn(t, func(st *serverTester) { st.fr.AllowIllegalWrites = true if err := st.fr.WriteContinuation(0, true, st.encodeHeader()); err != nil { t.Fatal(err) } }) } func TestServer_Rejects_PushPromise(t *testing.T) { testServerRejectsConn(t, func(st *serverTester) { pp := PushPromiseParam{ StreamID: 1, PromiseID: 3, } if err := st.fr.WritePushPromise(pp); err != nil { t.Fatal(err) } }) } // testServerRejectsConn tests that the server hangs up with a GOAWAY // frame and a server close after the client does something // deserving a CONNECTION_ERROR. func testServerRejectsConn(t *testing.T, writeReq func(*serverTester)) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {}) st.addLogFilter("connection error: PROTOCOL_ERROR") defer st.Close() st.greet() writeReq(st) st.wantGoAway() errc := make(chan error, 1) go func() { fr, err := st.fr.ReadFrame() if err == nil { err = fmt.Errorf("got frame of type %T", fr) } errc <- err }() select { case err := <-errc: if err != io.EOF { t.Errorf("ReadFrame = %v; want io.EOF", err) } case <-time.After(2 * time.Second): t.Error("timeout waiting for disconnect") } } // testServerRejectsStream tests that the server sends a RST_STREAM with the provided // error code after a client sends a bogus request. func testServerRejectsStream(t *testing.T, code ErrCode, writeReq func(*serverTester)) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {}) defer st.Close() st.greet() writeReq(st) st.wantRSTStream(1, code) } // testServerRequest sets up an idle HTTP/2 connection and lets you // write a single request with writeReq, and then verify that the // *http.Request is built correctly in checkReq. func testServerRequest(t *testing.T, writeReq func(*serverTester), checkReq func(*http.Request)) { gotReq := make(chan bool, 1) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { if r.Body == nil { t.Fatal("nil Body") } checkReq(r) gotReq <- true }) defer st.Close() st.greet() writeReq(st) select { case <-gotReq: case <-time.After(2 * time.Second): t.Error("timeout waiting for request") } } func getSlash(st *serverTester) { st.bodylessReq1() } func TestServer_Response_NoData(t *testing.T) { testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { // Nothing. return nil }, func(st *serverTester) { getSlash(st) hf := st.wantHeaders() if !hf.StreamEnded() { t.Fatal("want END_STREAM flag") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } }) } func TestServer_Response_NoData_Header_FooBar(t *testing.T) { testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { w.Header().Set("Foo-Bar", "some-value") return nil }, func(st *serverTester) { getSlash(st) hf := st.wantHeaders() if !hf.StreamEnded() { t.Fatal("want END_STREAM flag") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } goth := st.decodeHeader(hf.HeaderBlockFragment()) wanth := [][2]string{ {":status", "200"}, {"foo-bar", "some-value"}, {"content-type", "text/plain; charset=utf-8"}, {"content-length", "0"}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) } }) } func TestServer_Response_Data_Sniff_DoesntOverride(t *testing.T) { const msg = "this is HTML." testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { w.Header().Set("Content-Type", "foo/bar") io.WriteString(w, msg) return nil }, func(st *serverTester) { getSlash(st) hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("don't want END_STREAM, expecting data") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } goth := st.decodeHeader(hf.HeaderBlockFragment()) wanth := [][2]string{ {":status", "200"}, {"content-type", "foo/bar"}, {"content-length", strconv.Itoa(len(msg))}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) } df := st.wantData() if !df.StreamEnded() { t.Error("expected DATA to have END_STREAM flag") } if got := string(df.Data()); got != msg { t.Errorf("got DATA %q; want %q", got, msg) } }) } func TestServer_Response_TransferEncoding_chunked(t *testing.T) { const msg = "hi" testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { w.Header().Set("Transfer-Encoding", "chunked") // should be stripped io.WriteString(w, msg) return nil }, func(st *serverTester) { getSlash(st) hf := st.wantHeaders() goth := st.decodeHeader(hf.HeaderBlockFragment()) wanth := [][2]string{ {":status", "200"}, {"content-type", "text/plain; charset=utf-8"}, {"content-length", strconv.Itoa(len(msg))}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) } }) } // Header accessed only after the initial write. func TestServer_Response_Data_IgnoreHeaderAfterWrite_After(t *testing.T) { const msg = "this is HTML." testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { io.WriteString(w, msg) w.Header().Set("foo", "should be ignored") return nil }, func(st *serverTester) { getSlash(st) hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("unexpected END_STREAM") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } goth := st.decodeHeader(hf.HeaderBlockFragment()) wanth := [][2]string{ {":status", "200"}, {"content-type", "text/html; charset=utf-8"}, {"content-length", strconv.Itoa(len(msg))}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) } }) } // Header accessed before the initial write and later mutated. func TestServer_Response_Data_IgnoreHeaderAfterWrite_Overwrite(t *testing.T) { const msg = "this is HTML." testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { w.Header().Set("foo", "proper value") io.WriteString(w, msg) w.Header().Set("foo", "should be ignored") return nil }, func(st *serverTester) { getSlash(st) hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("unexpected END_STREAM") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } goth := st.decodeHeader(hf.HeaderBlockFragment()) wanth := [][2]string{ {":status", "200"}, {"foo", "proper value"}, {"content-type", "text/html; charset=utf-8"}, {"content-length", strconv.Itoa(len(msg))}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) } }) } func TestServer_Response_Data_SniffLenType(t *testing.T) { const msg = "this is HTML." testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { io.WriteString(w, msg) return nil }, func(st *serverTester) { getSlash(st) hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("don't want END_STREAM, expecting data") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } goth := st.decodeHeader(hf.HeaderBlockFragment()) wanth := [][2]string{ {":status", "200"}, {"content-type", "text/html; charset=utf-8"}, {"content-length", strconv.Itoa(len(msg))}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) } df := st.wantData() if !df.StreamEnded() { t.Error("expected DATA to have END_STREAM flag") } if got := string(df.Data()); got != msg { t.Errorf("got DATA %q; want %q", got, msg) } }) } func TestServer_Response_Header_Flush_MidWrite(t *testing.T) { const msg = "this is HTML" const msg2 = ", and this is the next chunk" testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { io.WriteString(w, msg) w.(http.Flusher).Flush() io.WriteString(w, msg2) return nil }, func(st *serverTester) { getSlash(st) hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("unexpected END_STREAM flag") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } goth := st.decodeHeader(hf.HeaderBlockFragment()) wanth := [][2]string{ {":status", "200"}, {"content-type", "text/html; charset=utf-8"}, // sniffed // and no content-length } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) } { df := st.wantData() if df.StreamEnded() { t.Error("unexpected END_STREAM flag") } if got := string(df.Data()); got != msg { t.Errorf("got DATA %q; want %q", got, msg) } } { df := st.wantData() if !df.StreamEnded() { t.Error("wanted END_STREAM flag on last data chunk") } if got := string(df.Data()); got != msg2 { t.Errorf("got DATA %q; want %q", got, msg2) } } }) } func TestServer_Response_LargeWrite(t *testing.T) { const size = 1 << 20 const maxFrameSize = 16 << 10 testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { n, err := w.Write(bytes.Repeat([]byte("a"), size)) if err != nil { return fmt.Errorf("Write error: %v", err) } if n != size { return fmt.Errorf("wrong size %d from Write", n) } return nil }, func(st *serverTester) { if err := st.fr.WriteSettings( Setting{SettingInitialWindowSize, 0}, Setting{SettingMaxFrameSize, maxFrameSize}, ); err != nil { t.Fatal(err) } st.wantSettingsAck() getSlash(st) // make the single request // Give the handler quota to write: if err := st.fr.WriteWindowUpdate(1, size); err != nil { t.Fatal(err) } // Give the handler quota to write to connection-level // window as well if err := st.fr.WriteWindowUpdate(0, size); err != nil { t.Fatal(err) } hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("unexpected END_STREAM flag") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } goth := st.decodeHeader(hf.HeaderBlockFragment()) wanth := [][2]string{ {":status", "200"}, {"content-type", "text/plain; charset=utf-8"}, // sniffed // and no content-length } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) } var bytes, frames int for { df := st.wantData() bytes += len(df.Data()) frames++ for _, b := range df.Data() { if b != 'a' { t.Fatal("non-'a' byte seen in DATA") } } if df.StreamEnded() { break } } if bytes != size { t.Errorf("Got %d bytes; want %d", bytes, size) } if want := int(size / maxFrameSize); frames < want || frames > want*2 { t.Errorf("Got %d frames; want %d", frames, size) } }) } // Test that the handler can't write more than the client allows func TestServer_Response_LargeWrite_FlowControlled(t *testing.T) { const size = 1 << 20 const maxFrameSize = 16 << 10 testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { w.(http.Flusher).Flush() n, err := w.Write(bytes.Repeat([]byte("a"), size)) if err != nil { return fmt.Errorf("Write error: %v", err) } if n != size { return fmt.Errorf("wrong size %d from Write", n) } return nil }, func(st *serverTester) { // Set the window size to something explicit for this test. // It's also how much initial data we expect. const initWindowSize = 123 if err := st.fr.WriteSettings( Setting{SettingInitialWindowSize, initWindowSize}, Setting{SettingMaxFrameSize, maxFrameSize}, ); err != nil { t.Fatal(err) } st.wantSettingsAck() getSlash(st) // make the single request defer func() { st.fr.WriteRSTStream(1, ErrCodeCancel) }() hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("unexpected END_STREAM flag") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } df := st.wantData() if got := len(df.Data()); got != initWindowSize { t.Fatalf("Initial window size = %d but got DATA with %d bytes", initWindowSize, got) } for _, quota := range []int{1, 13, 127} { if err := st.fr.WriteWindowUpdate(1, uint32(quota)); err != nil { t.Fatal(err) } df := st.wantData() if int(quota) != len(df.Data()) { t.Fatalf("read %d bytes after giving %d quota", len(df.Data()), quota) } } if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil { t.Fatal(err) } }) } // Test that the handler blocked in a Write is unblocked if the server sends a RST_STREAM. func TestServer_Response_RST_Unblocks_LargeWrite(t *testing.T) { const size = 1 << 20 const maxFrameSize = 16 << 10 testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { w.(http.Flusher).Flush() errc := make(chan error, 1) go func() { _, err := w.Write(bytes.Repeat([]byte("a"), size)) errc <- err }() select { case err := <-errc: if err == nil { return errors.New("unexpected nil error from Write in handler") } return nil case <-time.After(2 * time.Second): return errors.New("timeout waiting for Write in handler") } }, func(st *serverTester) { if err := st.fr.WriteSettings( Setting{SettingInitialWindowSize, 0}, Setting{SettingMaxFrameSize, maxFrameSize}, ); err != nil { t.Fatal(err) } st.wantSettingsAck() getSlash(st) // make the single request hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("unexpected END_STREAM flag") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } if err := st.fr.WriteRSTStream(1, ErrCodeCancel); err != nil { t.Fatal(err) } }) } func TestServer_Response_Empty_Data_Not_FlowControlled(t *testing.T) { testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { w.(http.Flusher).Flush() // Nothing; send empty DATA return nil }, func(st *serverTester) { // Handler gets no data quota: if err := st.fr.WriteSettings(Setting{SettingInitialWindowSize, 0}); err != nil { t.Fatal(err) } st.wantSettingsAck() getSlash(st) // make the single request hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("unexpected END_STREAM flag") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } df := st.wantData() if got := len(df.Data()); got != 0 { t.Fatalf("unexpected %d DATA bytes; want 0", got) } if !df.StreamEnded() { t.Fatal("DATA didn't have END_STREAM") } }) } func TestServer_Response_Automatic100Continue(t *testing.T) { const msg = "foo" const reply = "bar" testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { if v := r.Header.Get("Expect"); v != "" { t.Errorf("Expect header = %q; want empty", v) } buf := make([]byte, len(msg)) // This read should trigger the 100-continue being sent. if n, err := io.ReadFull(r.Body, buf); err != nil || n != len(msg) || string(buf) != msg { return fmt.Errorf("ReadFull = %q, %v; want %q, nil", buf[:n], err, msg) } _, err := io.WriteString(w, reply) return err }, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(":method", "POST", "expect", "100-continue"), EndStream: false, EndHeaders: true, }) hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("unexpected END_STREAM flag") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } goth := st.decodeHeader(hf.HeaderBlockFragment()) wanth := [][2]string{ {":status", "100"}, } if !reflect.DeepEqual(goth, wanth) { t.Fatalf("Got headers %v; want %v", goth, wanth) } // Okay, they sent status 100, so we can send our // gigantic and/or sensitive "foo" payload now. st.writeData(1, true, []byte(msg)) st.wantWindowUpdate(0, uint32(len(msg))) hf = st.wantHeaders() if hf.StreamEnded() { t.Fatal("expected data to follow") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } goth = st.decodeHeader(hf.HeaderBlockFragment()) wanth = [][2]string{ {":status", "200"}, {"content-type", "text/plain; charset=utf-8"}, {"content-length", strconv.Itoa(len(reply))}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Got headers %v; want %v", goth, wanth) } df := st.wantData() if string(df.Data()) != reply { t.Errorf("Client read %q; want %q", df.Data(), reply) } if !df.StreamEnded() { t.Errorf("expect data stream end") } }) } func TestServer_HandlerWriteErrorOnDisconnect(t *testing.T) { errc := make(chan error, 1) testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { p := []byte("some data.\n") for { _, err := w.Write(p) if err != nil { errc <- err return nil } } }, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(), EndStream: false, EndHeaders: true, }) hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("unexpected END_STREAM flag") } if !hf.HeadersEnded() { t.Fatal("want END_HEADERS flag") } // Close the connection and wait for the handler to (hopefully) notice. st.cc.Close() select { case <-errc: case <-time.After(5 * time.Second): t.Error("timeout") } }) } func TestServer_Rejects_Too_Many_Streams(t *testing.T) { const testPath = "/some/path" inHandler := make(chan uint32) leaveHandler := make(chan bool) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { id := w.(*responseWriter).rws.stream.id inHandler <- id if id == 1+(defaultMaxStreams+1)*2 && r.URL.Path != testPath { t.Errorf("decoded final path as %q; want %q", r.URL.Path, testPath) } <-leaveHandler }) defer st.Close() st.greet() nextStreamID := uint32(1) streamID := func() uint32 { defer func() { nextStreamID += 2 }() return nextStreamID } sendReq := func(id uint32, headers ...string) { st.writeHeaders(HeadersFrameParam{ StreamID: id, BlockFragment: st.encodeHeader(headers...), EndStream: true, EndHeaders: true, }) } for i := 0; i < defaultMaxStreams; i++ { sendReq(streamID()) <-inHandler } defer func() { for i := 0; i < defaultMaxStreams; i++ { leaveHandler <- true } }() // And this one should cross the limit: // (It's also sent as a CONTINUATION, to verify we still track the decoder context, // even if we're rejecting it) rejectID := streamID() headerBlock := st.encodeHeader(":path", testPath) frag1, frag2 := headerBlock[:3], headerBlock[3:] st.writeHeaders(HeadersFrameParam{ StreamID: rejectID, BlockFragment: frag1, EndStream: true, EndHeaders: false, // CONTINUATION coming }) if err := st.fr.WriteContinuation(rejectID, true, frag2); err != nil { t.Fatal(err) } st.wantRSTStream(rejectID, ErrCodeProtocol) // But let a handler finish: leaveHandler <- true st.wantHeaders() // And now another stream should be able to start: goodID := streamID() sendReq(goodID, ":path", testPath) select { case got := <-inHandler: if got != goodID { t.Errorf("Got stream %d; want %d", got, goodID) } case <-time.After(3 * time.Second): t.Error("timeout waiting for handler") } } // So many response headers that the server needs to use CONTINUATION frames: func TestServer_Response_ManyHeaders_With_Continuation(t *testing.T) { testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { h := w.Header() for i := 0; i < 5000; i++ { h.Set(fmt.Sprintf("x-header-%d", i), fmt.Sprintf("x-value-%d", i)) } return nil }, func(st *serverTester) { getSlash(st) hf := st.wantHeaders() if hf.HeadersEnded() { t.Fatal("got unwanted END_HEADERS flag") } n := 0 for { n++ cf := st.wantContinuation() if cf.HeadersEnded() { break } } if n < 5 { t.Errorf("Only got %d CONTINUATION frames; expected 5+ (currently 6)", n) } }) } // This previously crashed (reported by Mathieu Lonjaret as observed // while using Camlistore) because we got a DATA frame from the client // after the handler exited and our logic at the time was wrong, // keeping a stream in the map in stateClosed, which tickled an // invariant check later when we tried to remove that stream (via // defer sc.closeAllStreamsOnConnClose) when the serverConn serve loop // ended. func TestServer_NoCrash_HandlerClose_Then_ClientClose(t *testing.T) { testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { // nothing return nil }, func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(), EndStream: false, // DATA is coming EndHeaders: true, }) hf := st.wantHeaders() if !hf.HeadersEnded() || !hf.StreamEnded() { t.Fatalf("want END_HEADERS+END_STREAM, got %v", hf) } // Sent when the a Handler closes while a client has // indicated it's still sending DATA: st.wantRSTStream(1, ErrCodeCancel) // Now the handler has ended, so it's ended its // stream, but the client hasn't closed its side // (stateClosedLocal). So send more data and verify // it doesn't crash with an internal invariant panic, like // it did before. st.writeData(1, true, []byte("foo")) // Sent after a peer sends data anyway (admittedly the // previous RST_STREAM might've still been in-flight), // but they'll get the more friendly 'cancel' code // first. st.wantRSTStream(1, ErrCodeStreamClosed) // Set up a bunch of machinery to record the panic we saw // previously. var ( panMu sync.Mutex panicVal interface{} ) testHookOnPanicMu.Lock() testHookOnPanic = func(sc *serverConn, pv interface{}) bool { panMu.Lock() panicVal = pv panMu.Unlock() return true } testHookOnPanicMu.Unlock() // Now force the serve loop to end, via closing the connection. st.cc.Close() select { case <-st.sc.doneServing: // Loop has exited. panMu.Lock() got := panicVal panMu.Unlock() if got != nil { t.Errorf("Got panic: %v", got) } case <-time.After(5 * time.Second): t.Error("timeout") } }) } func TestServer_Rejects_TLS10(t *testing.T) { testRejectTLS(t, tls.VersionTLS10) } func TestServer_Rejects_TLS11(t *testing.T) { testRejectTLS(t, tls.VersionTLS11) } func testRejectTLS(t *testing.T, max uint16) { st := newServerTester(t, nil, func(c *tls.Config) { c.MaxVersion = max }) defer st.Close() gf := st.wantGoAway() if got, want := gf.ErrCode, ErrCodeInadequateSecurity; got != want { t.Errorf("Got error code %v; want %v", got, want) } } func TestServer_Rejects_TLSBadCipher(t *testing.T) { st := newServerTester(t, nil, func(c *tls.Config) { // Only list bad ones: c.CipherSuites = []uint16{ tls.TLS_RSA_WITH_RC4_128_SHA, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, tls.TLS_RSA_WITH_AES_128_CBC_SHA, tls.TLS_RSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, } }) defer st.Close() gf := st.wantGoAway() if got, want := gf.ErrCode, ErrCodeInadequateSecurity; got != want { t.Errorf("Got error code %v; want %v", got, want) } } func TestServer_Advertises_Common_Cipher(t *testing.T) { const requiredSuite = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 st := newServerTester(t, nil, func(c *tls.Config) { // Have the client only support the one required by the spec. c.CipherSuites = []uint16{requiredSuite} }, func(ts *httptest.Server) { var srv *http.Server = ts.Config // Have the server configured with no specific cipher suites. // This tests that Go's defaults include the required one. srv.TLSConfig = nil }) defer st.Close() st.greet() } func (st *serverTester) onHeaderField(f hpack.HeaderField) { if f.Name == "date" { return } st.decodedHeaders = append(st.decodedHeaders, [2]string{f.Name, f.Value}) } func (st *serverTester) decodeHeader(headerBlock []byte) (pairs [][2]string) { st.decodedHeaders = nil if _, err := st.hpackDec.Write(headerBlock); err != nil { st.t.Fatalf("hpack decoding error: %v", err) } if err := st.hpackDec.Close(); err != nil { st.t.Fatalf("hpack decoding error: %v", err) } return st.decodedHeaders } // testServerResponse sets up an idle HTTP/2 connection and lets you // write a single request with writeReq, and then reply to it in some way with the provided handler, // and then verify the output with the serverTester again (assuming the handler returns nil) func testServerResponse(t testing.TB, handler func(http.ResponseWriter, *http.Request) error, client func(*serverTester), ) { errc := make(chan error, 1) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { if r.Body == nil { t.Fatal("nil Body") } errc <- handler(w, r) }) defer st.Close() donec := make(chan bool) go func() { defer close(donec) st.greet() client(st) }() select { case <-donec: return case <-time.After(5 * time.Second): t.Fatal("timeout") } select { case err := <-errc: if err != nil { t.Fatalf("Error in handler: %v", err) } case <-time.After(2 * time.Second): t.Error("timeout waiting for handler to finish") } } // readBodyHandler returns an http Handler func that reads len(want) // bytes from r.Body and fails t if the contents read were not // the value of want. func readBodyHandler(t *testing.T, want string) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { buf := make([]byte, len(want)) _, err := io.ReadFull(r.Body, buf) if err != nil { t.Error(err) return } if string(buf) != want { t.Errorf("read %q; want %q", buf, want) } } } // TestServerWithCurl currently fails, hence the LenientCipherSuites test. See: // https://github.com/tatsuhiro-t/nghttp2/issues/140 & // http://sourceforge.net/p/curl/bugs/1472/ func TestServerWithCurl(t *testing.T) { testServerWithCurl(t, false) } func TestServerWithCurl_LenientCipherSuites(t *testing.T) { testServerWithCurl(t, true) } func testServerWithCurl(t *testing.T, permitProhibitedCipherSuites bool) { if runtime.GOOS != "linux" { t.Skip("skipping Docker test when not on Linux; requires --net which won't work with boot2docker anyway") } if testing.Short() { t.Skip("skipping curl test in short mode") } requireCurl(t) var gotConn int32 testHookOnConn = func() { atomic.StoreInt32(&gotConn, 1) } const msg = "Hello from curl!\n" ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Foo", "Bar") w.Header().Set("Client-Proto", r.Proto) io.WriteString(w, msg) })) ConfigureServer(ts.Config, &Server{ PermitProhibitedCipherSuites: permitProhibitedCipherSuites, }) ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config ts.StartTLS() defer ts.Close() t.Logf("Running test server for curl to hit at: %s", ts.URL) container := curl(t, "--silent", "--http2", "--insecure", "-v", ts.URL) defer kill(container) resc := make(chan interface{}, 1) go func() { res, err := dockerLogs(container) if err != nil { resc <- err } else { resc <- res } }() select { case res := <-resc: if err, ok := res.(error); ok { t.Fatal(err) } body := string(res.([]byte)) // Search for both "key: value" and "key:value", since curl changed their format // Our Dockerfile contains the latest version (no space), but just in case people // didn't rebuild, check both. if !strings.Contains(body, "foo: Bar") && !strings.Contains(body, "foo:Bar") { t.Errorf("didn't see foo: Bar header") t.Logf("Got: %s", body) } if !strings.Contains(body, "client-proto: HTTP/2") && !strings.Contains(body, "client-proto:HTTP/2") { t.Errorf("didn't see client-proto: HTTP/2 header") t.Logf("Got: %s", res) } if !strings.Contains(string(res.([]byte)), msg) { t.Errorf("didn't see %q content", msg) t.Logf("Got: %s", res) } case <-time.After(3 * time.Second): t.Errorf("timeout waiting for curl") } if atomic.LoadInt32(&gotConn) == 0 { t.Error("never saw an http2 connection") } } var doh2load = flag.Bool("h2load", false, "Run h2load test") func TestServerWithH2Load(t *testing.T) { if !*doh2load { t.Skip("Skipping without --h2load flag.") } if runtime.GOOS != "linux" { t.Skip("skipping Docker test when not on Linux; requires --net which won't work with boot2docker anyway") } requireH2load(t) msg := strings.Repeat("Hello, h2load!\n", 5000) ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, msg) w.(http.Flusher).Flush() io.WriteString(w, msg) })) ts.StartTLS() defer ts.Close() cmd := exec.Command("docker", "run", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl", "-n100000", "-c100", "-m100", ts.URL) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { t.Fatal(err) } } // Issue 12843 func TestServerDoS_MaxHeaderListSize(t *testing.T) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {}) defer st.Close() // shake hands st.writePreface() st.writeInitialSettings() frameSize := defaultMaxReadFrameSize var advHeaderListSize *uint32 st.wantSettings().ForeachSetting(func(s Setting) error { switch s.ID { case SettingMaxFrameSize: if s.Val < minMaxFrameSize { frameSize = minMaxFrameSize } else if s.Val > maxFrameSize { frameSize = maxFrameSize } else { frameSize = int(s.Val) } case SettingMaxHeaderListSize: advHeaderListSize = &s.Val } return nil }) st.writeSettingsAck() st.wantSettingsAck() if advHeaderListSize == nil { t.Errorf("server didn't advertise a max header list size") } else if *advHeaderListSize == 0 { t.Errorf("server advertised a max header list size of 0") } st.encodeHeaderField(":method", "GET") st.encodeHeaderField(":path", "/") st.encodeHeaderField(":scheme", "https") cookie := strings.Repeat("*", 4058) st.encodeHeaderField("cookie", cookie) st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.headerBuf.Bytes(), EndStream: true, EndHeaders: false, }) // Capture the short encoding of a duplicate ~4K cookie, now // that we've already sent it once. st.headerBuf.Reset() st.encodeHeaderField("cookie", cookie) // Now send 1MB of it. const size = 1 << 20 b := bytes.Repeat(st.headerBuf.Bytes(), size/st.headerBuf.Len()) for len(b) > 0 { chunk := b if len(chunk) > frameSize { chunk = chunk[:frameSize] } b = b[len(chunk):] st.fr.WriteContinuation(1, len(b) == 0, chunk) } h := st.wantHeaders() if !h.HeadersEnded() { t.Fatalf("Got HEADERS without END_HEADERS set: %v", h) } headers := st.decodeHeader(h.HeaderBlockFragment()) want := [][2]string{ {":status", "431"}, {"content-type", "text/html; charset=utf-8"}, {"content-length", "63"}, } if !reflect.DeepEqual(headers, want) { t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want) } } func TestCompressionErrorOnWrite(t *testing.T) { const maxStrLen = 8 << 10 var serverConfig *http.Server st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { // No response body. }, func(ts *httptest.Server) { serverConfig = ts.Config serverConfig.MaxHeaderBytes = maxStrLen }) st.addLogFilter("connection error: COMPRESSION_ERROR") defer st.Close() st.greet() maxAllowed := st.sc.maxHeaderStringLen() // Crank this up, now that we have a conn connected with the // hpack.Decoder's max string length set has been initialized // from the earlier low ~8K value. We want this higher so don't // hit the max header list size. We only want to test hitting // the max string size. serverConfig.MaxHeaderBytes = 1 << 20 // First a request with a header that's exactly the max allowed size. hbf := st.encodeHeader("foo", strings.Repeat("a", maxAllowed)) st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: hbf, EndStream: true, EndHeaders: true, }) h := st.wantHeaders() if !h.HeadersEnded() || !h.StreamEnded() { t.Errorf("Unexpected HEADER frame %v", h) } // And now send one that's just one byte too big. hbf = st.encodeHeader("bar", strings.Repeat("b", maxAllowed+1)) st.writeHeaders(HeadersFrameParam{ StreamID: 3, BlockFragment: hbf, EndStream: true, EndHeaders: true, }) ga := st.wantGoAway() if ga.ErrCode != ErrCodeCompression { t.Errorf("GOAWAY err = %v; want ErrCodeCompression", ga.ErrCode) } } func TestCompressionErrorOnClose(t *testing.T) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { // No response body. }) st.addLogFilter("connection error: COMPRESSION_ERROR") defer st.Close() st.greet() hbf := st.encodeHeader("foo", "bar") hbf = hbf[:len(hbf)-1] // truncate one byte from the end, so hpack.Decoder.Close fails. st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: hbf, EndStream: true, EndHeaders: true, }) ga := st.wantGoAway() if ga.ErrCode != ErrCodeCompression { t.Errorf("GOAWAY err = %v; want ErrCodeCompression", ga.ErrCode) } } // test that a server handler can read trailers from a client func TestServerReadsTrailers(t *testing.T) { const testBody = "some test body" writeReq := func(st *serverTester) { st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader("trailer", "Foo, Bar", "trailer", "Baz"), EndStream: false, EndHeaders: true, }) st.writeData(1, false, []byte(testBody)) st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeaderRaw( "foo", "foov", "bar", "barv", "baz", "bazv", "surprise", "wasn't declared; shouldn't show up", ), EndStream: true, EndHeaders: true, }) } checkReq := func(r *http.Request) { wantTrailer := http.Header{ "Foo": nil, "Bar": nil, "Baz": nil, } if !reflect.DeepEqual(r.Trailer, wantTrailer) { t.Errorf("initial Trailer = %v; want %v", r.Trailer, wantTrailer) } slurp, err := ioutil.ReadAll(r.Body) if string(slurp) != testBody { t.Errorf("read body %q; want %q", slurp, testBody) } if err != nil { t.Fatalf("Body slurp: %v", err) } wantTrailerAfter := http.Header{ "Foo": {"foov"}, "Bar": {"barv"}, "Baz": {"bazv"}, } if !reflect.DeepEqual(r.Trailer, wantTrailerAfter) { t.Errorf("final Trailer = %v; want %v", r.Trailer, wantTrailerAfter) } } testServerRequest(t, writeReq, checkReq) } // test that a server handler can send trailers func TestServerWritesTrailers_WithFlush(t *testing.T) { testServerWritesTrailers(t, true) } func TestServerWritesTrailers_WithoutFlush(t *testing.T) { testServerWritesTrailers(t, false) } func testServerWritesTrailers(t *testing.T, withFlush bool) { // See https://httpwg.github.io/specs/rfc7540.html#rfc.section.8.1.3 testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error { w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B") w.Header().Add("Trailer", "Server-Trailer-C") // TODO: decide if the server should filter these while // writing the Trailer header in the response. Currently it // appears net/http doesn't do this for http/1.1 w.Header().Add("Trailer", "Transfer-Encoding, Content-Length, Trailer") // filtered w.Header().Set("Foo", "Bar") w.Header().Set("Content-Length", "5") io.WriteString(w, "Hello") if withFlush { w.(http.Flusher).Flush() } w.Header().Set("Server-Trailer-A", "valuea") w.Header().Set("Server-Trailer-C", "valuec") // skipping B w.Header().Set("Server-Surpise", "surprise! this isn't predeclared!") w.Header().Set("Transfer-Encoding", "should not be included; Forbidden by RFC 2616 14.40") w.Header().Set("Content-Length", "should not be included; Forbidden by RFC 2616 14.40") w.Header().Set("Trailer", "should not be included; Forbidden by RFC 2616 14.40") return nil }, func(st *serverTester) { getSlash(st) hf := st.wantHeaders() if hf.StreamEnded() { t.Fatal("response HEADERS had END_STREAM") } if !hf.HeadersEnded() { t.Fatal("response HEADERS didn't have END_HEADERS") } goth := st.decodeHeader(hf.HeaderBlockFragment()) wanth := [][2]string{ {":status", "200"}, {"foo", "Bar"}, {"trailer", "Server-Trailer-A, Server-Trailer-B"}, {"trailer", "Server-Trailer-C"}, {"trailer", "Transfer-Encoding, Content-Length, Trailer"}, {"content-type", "text/plain; charset=utf-8"}, {"content-length", "5"}, } if !reflect.DeepEqual(goth, wanth) { t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth) } df := st.wantData() if string(df.Data()) != "Hello" { t.Fatalf("Client read %q; want Hello", df.Data()) } if df.StreamEnded() { t.Fatalf("data frame had STREAM_ENDED") } tf := st.wantHeaders() // for the trailers if !tf.StreamEnded() { t.Fatalf("trailers HEADERS lacked END_STREAM") } if !tf.HeadersEnded() { t.Fatalf("trailers HEADERS lacked END_HEADERS") } wanth = [][2]string{ {"server-trailer-a", "valuea"}, {"server-trailer-c", "valuec"}, } goth = st.decodeHeader(tf.HeaderBlockFragment()) if !reflect.DeepEqual(goth, wanth) { t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth) } }) } func BenchmarkServerGets(b *testing.B) { b.ReportAllocs() const msg = "Hello, world" st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, msg) }) defer st.Close() st.greet() // Give the server quota to reply. (plus it has the the 64KB) if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { id := 1 + uint32(i)*2 st.writeHeaders(HeadersFrameParam{ StreamID: id, BlockFragment: st.encodeHeader(), EndStream: true, EndHeaders: true, }) st.wantHeaders() df := st.wantData() if !df.StreamEnded() { b.Fatalf("DATA didn't have END_STREAM; got %v", df) } } } func BenchmarkServerPosts(b *testing.B) { b.ReportAllocs() const msg = "Hello, world" st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, msg) }) defer st.Close() st.greet() // Give the server quota to reply. (plus it has the the 64KB) if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { id := 1 + uint32(i)*2 st.writeHeaders(HeadersFrameParam{ StreamID: id, BlockFragment: st.encodeHeader(":method", "POST"), EndStream: false, EndHeaders: true, }) st.writeData(id, true, nil) st.wantHeaders() df := st.wantData() if !df.StreamEnded() { b.Fatalf("DATA didn't have END_STREAM; got %v", df) } } } // go-fuzz bug, originally reported at https://github.com/bradfitz/http2/issues/53 // Verify we don't hang. func TestIssue53(t *testing.T) { const data = "PRI * HTTP/2.0\r\n\r\nSM" + "\r\n\r\n\x00\x00\x00\x01\ainfinfin\ad" s := &http.Server{ ErrorLog: log.New(io.MultiWriter(stderrv(), twriter{t: t}), "", log.LstdFlags), } s2 := &Server{MaxReadFrameSize: 1 << 16, PermitProhibitedCipherSuites: true} c := &issue53Conn{[]byte(data), false, false} s2.handleConn(s, c, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello")) })) if !c.closed { t.Fatal("connection is not closed") } } type issue53Conn struct { data []byte closed bool written bool } func (c *issue53Conn) Read(b []byte) (n int, err error) { if len(c.data) == 0 { return 0, io.EOF } n = copy(b, c.data) c.data = c.data[n:] return } func (c *issue53Conn) Write(b []byte) (n int, err error) { c.written = true return len(b), nil } func (c *issue53Conn) Close() error { c.closed = true return nil } func (c *issue53Conn) LocalAddr() net.Addr { return &net.TCPAddr{net.IP{127, 0, 0, 1}, 49706, ""} } func (c *issue53Conn) RemoteAddr() net.Addr { return &net.TCPAddr{net.IP{127, 0, 0, 1}, 49706, ""} } func (c *issue53Conn) SetDeadline(t time.Time) error { return nil } func (c *issue53Conn) SetReadDeadline(t time.Time) error { return nil } func (c *issue53Conn) SetWriteDeadline(t time.Time) error { return nil } // golang.org/issue/12895 func TestConfigureServer(t *testing.T) { tests := []struct { name string in http.Server wantErr string }{ { name: "empty server", in: http.Server{}, }, { name: "just the required cipher suite", in: http.Server{ TLSConfig: &tls.Config{ CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, }, }, }, { name: "missing required cipher suite", in: http.Server{ TLSConfig: &tls.Config{ CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, }, }, wantErr: "is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", }, { name: "required after bad", in: http.Server{ TLSConfig: &tls.Config{ CipherSuites: []uint16{tls.TLS_RSA_WITH_RC4_128_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, }, }, wantErr: "contains an HTTP/2-approved cipher suite (0xc02f), but it comes after", }, { name: "bad after required", in: http.Server{ TLSConfig: &tls.Config{ CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_RSA_WITH_RC4_128_SHA}, }, }, }, } for _, tt := range tests { err := ConfigureServer(&tt.in, nil) if (err != nil) != (tt.wantErr != "") { if tt.wantErr != "" { t.Errorf("%s: success, but want error", tt.name) } else { t.Errorf("%s: unexpected error: %v", tt.name, err) } } if err != nil && tt.wantErr != "" && !strings.Contains(err.Error(), tt.wantErr) { t.Errorf("%s: err = %v; want substring %q", tt.name, err, tt.wantErr) } if err == nil && !tt.in.TLSConfig.PreferServerCipherSuites { t.Errorf("%s: PreferServerCipherSuite is false; want true", tt.name) } } } func TestServerRejectHeadWithBody(t *testing.T) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { // No response body. }) defer st.Close() st.greet() st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(":method", "HEAD"), EndStream: false, // what we're testing, a bogus HEAD request with body EndHeaders: true, }) st.wantRSTStream(1, ErrCodeProtocol) } func TestServerNoAutoContentLengthOnHead(t *testing.T) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { // No response body. (or smaller than one frame) }) defer st.Close() st.greet() st.writeHeaders(HeadersFrameParam{ StreamID: 1, // clients send odd numbers BlockFragment: st.encodeHeader(":method", "HEAD"), EndStream: true, EndHeaders: true, }) h := st.wantHeaders() headers := st.decodeHeader(h.HeaderBlockFragment()) want := [][2]string{ {":status", "200"}, {"content-type", "text/plain; charset=utf-8"}, } if !reflect.DeepEqual(headers, want) { t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want) } } // golang.org/issue/13495 func TestServerNoDuplicateContentType(t *testing.T) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { w.Header()["Content-Type"] = []string{""} fmt.Fprintf(w, "hi") }) defer st.Close() st.greet() st.writeHeaders(HeadersFrameParam{ StreamID: 1, BlockFragment: st.encodeHeader(), EndStream: true, EndHeaders: true, }) h := st.wantHeaders() headers := st.decodeHeader(h.HeaderBlockFragment()) want := [][2]string{ {":status", "200"}, {"content-type", ""}, {"content-length", "41"}, } if !reflect.DeepEqual(headers, want) { t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/testdata/000077500000000000000000000000001264464372400233125ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/testdata/draft-ietf-httpbis-http2.xml000066400000000000000000007672651264464372400306220ustar00rootroot00000000000000 Hypertext Transfer Protocol version 2 Twist
    mbelshe@chromium.org
    Google, Inc
    fenix@google.com
    Mozilla
    331 E Evelyn Street Mountain View CA 94041 US martin.thomson@gmail.com
    Applications HTTPbis HTTP SPDY Web This specification describes an optimized expression of the semantics of the Hypertext Transfer Protocol (HTTP). HTTP/2 enables a more efficient use of network resources and a reduced perception of latency by introducing header field compression and allowing multiple concurrent messages on the same connection. It also introduces unsolicited push of representations from servers to clients. This specification is an alternative to, but does not obsolete, the HTTP/1.1 message syntax. HTTP's existing semantics remain unchanged. Discussion of this draft takes place on the HTTPBIS working group mailing list (ietf-http-wg@w3.org), which is archived at . Working Group information can be found at ; that specific to HTTP/2 are at . The changes in this draft are summarized in .
    The Hypertext Transfer Protocol (HTTP) is a wildly successful protocol. However, the HTTP/1.1 message format () has several characteristics that have a negative overall effect on application performance today. In particular, HTTP/1.0 allowed only one request to be outstanding at a time on a given TCP connection. HTTP/1.1 added request pipelining, but this only partially addressed request concurrency and still suffers from head-of-line blocking. Therefore, HTTP/1.1 clients that need to make many requests typically use multiple connections to a server in order to achieve concurrency and thereby reduce latency. Furthermore, HTTP header fields are often repetitive and verbose, causing unnecessary network traffic, as well as causing the initial TCP congestion window to quickly fill. This can result in excessive latency when multiple requests are made on a new TCP connection. HTTP/2 addresses these issues by defining an optimized mapping of HTTP's semantics to an underlying connection. Specifically, it allows interleaving of request and response messages on the same connection and uses an efficient coding for HTTP header fields. It also allows prioritization of requests, letting more important requests complete more quickly, further improving performance. The resulting protocol is more friendly to the network, because fewer TCP connections can be used in comparison to HTTP/1.x. This means less competition with other flows, and longer-lived connections, which in turn leads to better utilization of available network capacity. Finally, HTTP/2 also enables more efficient processing of messages through use of binary message framing.
    HTTP/2 provides an optimized transport for HTTP semantics. HTTP/2 supports all of the core features of HTTP/1.1, but aims to be more efficient in several ways. The basic protocol unit in HTTP/2 is a frame. Each frame type serves a different purpose. For example, HEADERS and DATA frames form the basis of HTTP requests and responses; other frame types like SETTINGS, WINDOW_UPDATE, and PUSH_PROMISE are used in support of other HTTP/2 features. Multiplexing of requests is achieved by having each HTTP request-response exchange associated with its own stream. Streams are largely independent of each other, so a blocked or stalled request or response does not prevent progress on other streams. Flow control and prioritization ensure that it is possible to efficiently use multiplexed streams. Flow control helps to ensure that only data that can be used by a receiver is transmitted. Prioritization ensures that limited resources can be directed to the most important streams first. HTTP/2 adds a new interaction mode, whereby a server can push responses to a client. Server push allows a server to speculatively send a client data that the server anticipates the client will need, trading off some network usage against a potential latency gain. The server does this by synthesizing a request, which it sends as a PUSH_PROMISE frame. The server is then able to send a response to the synthetic request on a separate stream. Frames that contain HTTP header fields are compressed. HTTP requests can be highly redundant, so compression can reduce the size of requests and responses significantly.
    The HTTP/2 specification is split into four parts: Starting HTTP/2 covers how an HTTP/2 connection is initiated. The framing and streams layers describe the way HTTP/2 frames are structured and formed into multiplexed streams. Frame and error definitions include details of the frame and error types used in HTTP/2. HTTP mappings and additional requirements describe how HTTP semantics are expressed using frames and streams. While some of the frame and stream layer concepts are isolated from HTTP, this specification does not define a completely generic framing layer. The framing and streams layers are tailored to the needs of the HTTP protocol and server push.
    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. All numeric values are in network byte order. Values are unsigned unless otherwise indicated. Literal values are provided in decimal or hexadecimal as appropriate. Hexadecimal literals are prefixed with 0x to distinguish them from decimal literals. The following terms are used: The endpoint initiating the HTTP/2 connection. A transport-layer connection between two endpoints. An error that affects the entire HTTP/2 connection. Either the client or server of the connection. The smallest unit of communication within an HTTP/2 connection, consisting of a header and a variable-length sequence of octets structured according to the frame type. An endpoint. When discussing a particular endpoint, "peer" refers to the endpoint that is remote to the primary subject of discussion. An endpoint that is receiving frames. An endpoint that is transmitting frames. The endpoint which did not initiate the HTTP/2 connection. A bi-directional flow of frames across a virtual channel within the HTTP/2 connection. An error on the individual HTTP/2 stream. Finally, the terms "gateway", "intermediary", "proxy", and "tunnel" are defined in .
    An HTTP/2 connection is an application layer protocol running on top of a TCP connection (). The client is the TCP connection initiator. HTTP/2 uses the same "http" and "https" URI schemes used by HTTP/1.1. HTTP/2 shares the same default port numbers: 80 for "http" URIs and 443 for "https" URIs. As a result, implementations processing requests for target resource URIs like http://example.org/foo or https://example.com/bar are required to first discover whether the upstream server (the immediate peer to which the client wishes to establish a connection) supports HTTP/2. The means by which support for HTTP/2 is determined is different for "http" and "https" URIs. Discovery for "http" URIs is described in . Discovery for "https" URIs is described in .
    The protocol defined in this document has two identifiers. The string "h2" identifies the protocol where HTTP/2 uses TLS. This identifier is used in the TLS application layer protocol negotiation extension (ALPN) field and any place that HTTP/2 over TLS is identified. The "h2" string is serialized into an ALPN protocol identifier as the two octet sequence: 0x68, 0x32. The string "h2c" identifies the protocol where HTTP/2 is run over cleartext TCP. This identifier is used in the HTTP/1.1 Upgrade header field and any place that HTTP/2 over TCP is identified. Negotiating "h2" or "h2c" implies the use of the transport, security, framing and message semantics described in this document. RFC Editor's Note: please remove the remainder of this section prior to the publication of a final version of this document. Only implementations of the final, published RFC can identify themselves as "h2" or "h2c". Until such an RFC exists, implementations MUST NOT identify themselves using these strings. Examples and text throughout the rest of this document use "h2" as a matter of editorial convenience only. Implementations of draft versions MUST NOT identify using this string. Implementations of draft versions of the protocol MUST add the string "-" and the corresponding draft number to the identifier. For example, draft-ietf-httpbis-http2-11 over TLS is identified using the string "h2-11". Non-compatible experiments that are based on these draft versions MUST append the string "-" and an experiment name to the identifier. For example, an experimental implementation of packet mood-based encoding based on draft-ietf-httpbis-http2-09 might identify itself as "h2-09-emo". Note that any label MUST conform to the "token" syntax defined in . Experimenters are encouraged to coordinate their experiments on the ietf-http-wg@w3.org mailing list.
    A client that makes a request for an "http" URI without prior knowledge about support for HTTP/2 uses the HTTP Upgrade mechanism (). The client makes an HTTP/1.1 request that includes an Upgrade header field identifying HTTP/2 with the "h2c" token. The HTTP/1.1 request MUST include exactly one HTTP2-Settings header field.
    For example: ]]>
    Requests that contain an entity body MUST be sent in their entirety before the client can send HTTP/2 frames. This means that a large request entity can block the use of the connection until it is completely sent. If concurrency of an initial request with subsequent requests is important, an OPTIONS request can be used to perform the upgrade to HTTP/2, at the cost of an additional round-trip. A server that does not support HTTP/2 can respond to the request as though the Upgrade header field were absent:
    HTTP/1.1 200 OK Content-Length: 243 Content-Type: text/html ...
    A server MUST ignore a "h2" token in an Upgrade header field. Presence of a token with "h2" implies HTTP/2 over TLS, which is instead negotiated as described in . A server that supports HTTP/2 can accept the upgrade with a 101 (Switching Protocols) response. After the empty line that terminates the 101 response, the server can begin sending HTTP/2 frames. These frames MUST include a response to the request that initiated the Upgrade.
    For example: HTTP/1.1 101 Switching Protocols Connection: Upgrade Upgrade: h2c [ HTTP/2 connection ...
    The first HTTP/2 frame sent by the server is a SETTINGS frame () as the server connection preface (). Upon receiving the 101 response, the client sends a connection preface, which includes a SETTINGS frame. The HTTP/1.1 request that is sent prior to upgrade is assigned stream identifier 1 and is assigned default priority values. Stream 1 is implicitly half closed from the client toward the server, since the request is completed as an HTTP/1.1 request. After commencing the HTTP/2 connection, stream 1 is used for the response.
    A request that upgrades from HTTP/1.1 to HTTP/2 MUST include exactly one HTTP2-Settings header field. The HTTP2-Settings header field is a connection-specific header field that includes parameters that govern the HTTP/2 connection, provided in anticipation of the server accepting the request to upgrade.
    A server MUST NOT upgrade the connection to HTTP/2 if this header field is not present, or if more than one is present. A server MUST NOT send this header field. The content of the HTTP2-Settings header field is the payload of a SETTINGS frame (), encoded as a base64url string (that is, the URL- and filename-safe Base64 encoding described in , with any trailing '=' characters omitted). The ABNF production for token68 is defined in . Since the upgrade is only intended to apply to the immediate connection, a client sending HTTP2-Settings MUST also send HTTP2-Settings as a connection option in the Connection header field to prevent it from being forwarded downstream. A server decodes and interprets these values as it would any other SETTINGS frame. Acknowledgement of the SETTINGS parameters is not necessary, since a 101 response serves as implicit acknowledgment. Providing these values in the Upgrade request gives a client an opportunity to provide parameters prior to receiving any frames from the server.
    A client that makes a request to an "https" URI uses TLS with the application layer protocol negotiation extension. HTTP/2 over TLS uses the "h2" application token. The "h2c" token MUST NOT be sent by a client or selected by a server. Once TLS negotiation is complete, both the client and the server send a connection preface.
    A client can learn that a particular server supports HTTP/2 by other means. For example, describes a mechanism for advertising this capability. A client MAY immediately send HTTP/2 frames to a server that is known to support HTTP/2, after the connection preface; a server can identify such a connection by the presence of the connection preface. This only affects the establishment of HTTP/2 connections over cleartext TCP; implementations that support HTTP/2 over TLS MUST use protocol negotiation in TLS. Without additional information, prior support for HTTP/2 is not a strong signal that a given server will support HTTP/2 for future connections. For example, it is possible for server configurations to change, for configurations to differ between instances in clustered servers, or for network conditions to change.
    Upon establishment of a TCP connection and determination that HTTP/2 will be used by both peers, each endpoint MUST send a connection preface as a final confirmation and to establish the initial SETTINGS parameters for the HTTP/2 connection. The client and server each send a different connection preface. The client connection preface starts with a sequence of 24 octets, which in hex notation are:
    (the string PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n). This sequence is followed by a SETTINGS frame (). The SETTINGS frame MAY be empty. The client sends the client connection preface immediately upon receipt of a 101 Switching Protocols response (indicating a successful upgrade), or as the first application data octets of a TLS connection. If starting an HTTP/2 connection with prior knowledge of server support for the protocol, the client connection preface is sent upon connection establishment. The client connection preface is selected so that a large proportion of HTTP/1.1 or HTTP/1.0 servers and intermediaries do not attempt to process further frames. Note that this does not address the concerns raised in . The server connection preface consists of a potentially empty SETTINGS frame () that MUST be the first frame the server sends in the HTTP/2 connection. The SETTINGS frames received from a peer as part of the connection preface MUST be acknowledged (see ) after sending the connection preface. To avoid unnecessary latency, clients are permitted to send additional frames to the server immediately after sending the client connection preface, without waiting to receive the server connection preface. It is important to note, however, that the server connection preface SETTINGS frame might include parameters that necessarily alter how a client is expected to communicate with the server. Upon receiving the SETTINGS frame, the client is expected to honor any parameters established. In some configurations, it is possible for the server to transmit SETTINGS before the client sends additional frames, providing an opportunity to avoid this issue. Clients and servers MUST treat an invalid connection preface as a connection error of type PROTOCOL_ERROR. A GOAWAY frame () MAY be omitted in this case, since an invalid preface indicates that the peer is not using HTTP/2.
    Once the HTTP/2 connection is established, endpoints can begin exchanging frames.
    All frames begin with a fixed 9-octet header followed by a variable-length payload.
    The fields of the frame header are defined as: The length of the frame payload expressed as an unsigned 24-bit integer. Values greater than 214 (16,384) MUST NOT be sent unless the receiver has set a larger value for SETTINGS_MAX_FRAME_SIZE. The 9 octets of the frame header are not included in this value. The 8-bit type of the frame. The frame type determines the format and semantics of the frame. Implementations MUST ignore and discard any frame that has a type that is unknown. An 8-bit field reserved for frame-type specific boolean flags. Flags are assigned semantics specific to the indicated frame type. Flags that have no defined semantics for a particular frame type MUST be ignored, and MUST be left unset (0) when sending. A reserved 1-bit field. The semantics of this bit are undefined and the bit MUST remain unset (0) when sending and MUST be ignored when receiving. A 31-bit stream identifier (see ). The value 0 is reserved for frames that are associated with the connection as a whole as opposed to an individual stream. The structure and content of the frame payload is dependent entirely on the frame type.
    The size of a frame payload is limited by the maximum size that a receiver advertises in the SETTINGS_MAX_FRAME_SIZE setting. This setting can have any value between 214 (16,384) and 224-1 (16,777,215) octets, inclusive. All implementations MUST be capable of receiving and minimally processing frames up to 214 octets in length, plus the 9 octet frame header. The size of the frame header is not included when describing frame sizes. Certain frame types, such as PING, impose additional limits on the amount of payload data allowed. If a frame size exceeds any defined limit, or is too small to contain mandatory frame data, the endpoint MUST send a FRAME_SIZE_ERROR error. A frame size error in a frame that could alter the state of the entire connection MUST be treated as a connection error; this includes any frame carrying a header block (that is, HEADERS, PUSH_PROMISE, and CONTINUATION), SETTINGS, and any WINDOW_UPDATE frame with a stream identifier of 0. Endpoints are not obligated to use all available space in a frame. Responsiveness can be improved by using frames that are smaller than the permitted maximum size. Sending large frames can result in delays in sending time-sensitive frames (such RST_STREAM, WINDOW_UPDATE, or PRIORITY) which if blocked by the transmission of a large frame, could affect performance.
    Just as in HTTP/1, a header field in HTTP/2 is a name with one or more associated values. They are used within HTTP request and response messages as well as server push operations (see ). Header lists are collections of zero or more header fields. When transmitted over a connection, a header list is serialized into a header block using HTTP Header Compression. The serialized header block is then divided into one or more octet sequences, called header block fragments, and transmitted within the payload of HEADERS, PUSH_PROMISE or CONTINUATION frames. The Cookie header field is treated specially by the HTTP mapping (see ). A receiving endpoint reassembles the header block by concatenating its fragments, then decompresses the block to reconstruct the header list. A complete header block consists of either: a single HEADERS or PUSH_PROMISE frame, with the END_HEADERS flag set, or a HEADERS or PUSH_PROMISE frame with the END_HEADERS flag cleared and one or more CONTINUATION frames, where the last CONTINUATION frame has the END_HEADERS flag set. Header compression is stateful. One compression context and one decompression context is used for the entire connection. Each header block is processed as a discrete unit. Header blocks MUST be transmitted as a contiguous sequence of frames, with no interleaved frames of any other type or from any other stream. The last frame in a sequence of HEADERS or CONTINUATION frames MUST have the END_HEADERS flag set. The last frame in a sequence of PUSH_PROMISE or CONTINUATION frames MUST have the END_HEADERS flag set. This allows a header block to be logically equivalent to a single frame. Header block fragments can only be sent as the payload of HEADERS, PUSH_PROMISE or CONTINUATION frames, because these frames carry data that can modify the compression context maintained by a receiver. An endpoint receiving HEADERS, PUSH_PROMISE or CONTINUATION frames MUST reassemble header blocks and perform decompression even if the frames are to be discarded. A receiver MUST terminate the connection with a connection error of type COMPRESSION_ERROR if it does not decompress a header block.
    A "stream" is an independent, bi-directional sequence of frames exchanged between the client and server within an HTTP/2 connection. Streams have several important characteristics: A single HTTP/2 connection can contain multiple concurrently open streams, with either endpoint interleaving frames from multiple streams. Streams can be established and used unilaterally or shared by either the client or server. Streams can be closed by either endpoint. The order in which frames are sent on a stream is significant. Recipients process frames in the order they are received. In particular, the order of HEADERS, and DATA frames is semantically significant. Streams are identified by an integer. Stream identifiers are assigned to streams by the endpoint initiating the stream.
    The lifecycle of a stream is shown in .
    | |<-----------' | | R | closed | R | `-------------------->| |<--------------------' +--------+ H: HEADERS frame (with implied CONTINUATIONs) PP: PUSH_PROMISE frame (with implied CONTINUATIONs) ES: END_STREAM flag R: RST_STREAM frame ]]>
    Note that this diagram shows stream state transitions and the frames and flags that affect those transitions only. In this regard, CONTINUATION frames do not result in state transitions; they are effectively part of the HEADERS or PUSH_PROMISE that they follow. For this purpose, the END_STREAM flag is processed as a separate event to the frame that bears it; a HEADERS frame with the END_STREAM flag set can cause two state transitions. Both endpoints have a subjective view of the state of a stream that could be different when frames are in transit. Endpoints do not coordinate the creation of streams; they are created unilaterally by either endpoint. The negative consequences of a mismatch in states are limited to the "closed" state after sending RST_STREAM, where frames might be received for some time after closing. Streams have the following states: All streams start in the "idle" state. In this state, no frames have been exchanged. The following transitions are valid from this state: Sending or receiving a HEADERS frame causes the stream to become "open". The stream identifier is selected as described in . The same HEADERS frame can also cause a stream to immediately become "half closed". Sending a PUSH_PROMISE frame marks the associated stream for later use. The stream state for the reserved stream transitions to "reserved (local)". Receiving a PUSH_PROMISE frame marks the associated stream as reserved by the remote peer. The state of the stream becomes "reserved (remote)". Receiving any frames other than HEADERS or PUSH_PROMISE on a stream in this state MUST be treated as a connection error of type PROTOCOL_ERROR. A stream in the "reserved (local)" state is one that has been promised by sending a PUSH_PROMISE frame. A PUSH_PROMISE frame reserves an idle stream by associating the stream with an open stream that was initiated by the remote peer (see ). In this state, only the following transitions are possible: The endpoint can send a HEADERS frame. This causes the stream to open in a "half closed (remote)" state. Either endpoint can send a RST_STREAM frame to cause the stream to become "closed". This releases the stream reservation. An endpoint MUST NOT send any type of frame other than HEADERS or RST_STREAM in this state. A PRIORITY frame MAY be received in this state. Receiving any type of frame other than RST_STREAM or PRIORITY on a stream in this state MUST be treated as a connection error of type PROTOCOL_ERROR. A stream in the "reserved (remote)" state has been reserved by a remote peer. In this state, only the following transitions are possible: Receiving a HEADERS frame causes the stream to transition to "half closed (local)". Either endpoint can send a RST_STREAM frame to cause the stream to become "closed". This releases the stream reservation. An endpoint MAY send a PRIORITY frame in this state to reprioritize the reserved stream. An endpoint MUST NOT send any type of frame other than RST_STREAM, WINDOW_UPDATE, or PRIORITY in this state. Receiving any type of frame other than HEADERS or RST_STREAM on a stream in this state MUST be treated as a connection error of type PROTOCOL_ERROR. A stream in the "open" state may be used by both peers to send frames of any type. In this state, sending peers observe advertised stream level flow control limits. From this state either endpoint can send a frame with an END_STREAM flag set, which causes the stream to transition into one of the "half closed" states: an endpoint sending an END_STREAM flag causes the stream state to become "half closed (local)"; an endpoint receiving an END_STREAM flag causes the stream state to become "half closed (remote)". Either endpoint can send a RST_STREAM frame from this state, causing it to transition immediately to "closed". A stream that is in the "half closed (local)" state cannot be used for sending frames. Only WINDOW_UPDATE, PRIORITY and RST_STREAM frames can be sent in this state. A stream transitions from this state to "closed" when a frame that contains an END_STREAM flag is received, or when either peer sends a RST_STREAM frame. A receiver can ignore WINDOW_UPDATE frames in this state, which might arrive for a short period after a frame bearing the END_STREAM flag is sent. PRIORITY frames received in this state are used to reprioritize streams that depend on the current stream. A stream that is "half closed (remote)" is no longer being used by the peer to send frames. In this state, an endpoint is no longer obligated to maintain a receiver flow control window if it performs flow control. If an endpoint receives additional frames for a stream that is in this state, other than WINDOW_UPDATE, PRIORITY or RST_STREAM, it MUST respond with a stream error of type STREAM_CLOSED. A stream that is "half closed (remote)" can be used by the endpoint to send frames of any type. In this state, the endpoint continues to observe advertised stream level flow control limits. A stream can transition from this state to "closed" by sending a frame that contains an END_STREAM flag, or when either peer sends a RST_STREAM frame. The "closed" state is the terminal state. An endpoint MUST NOT send frames other than PRIORITY on a closed stream. An endpoint that receives any frame other than PRIORITY after receiving a RST_STREAM MUST treat that as a stream error of type STREAM_CLOSED. Similarly, an endpoint that receives any frames after receiving a frame with the END_STREAM flag set MUST treat that as a connection error of type STREAM_CLOSED, unless the frame is permitted as described below. WINDOW_UPDATE or RST_STREAM frames can be received in this state for a short period after a DATA or HEADERS frame containing an END_STREAM flag is sent. Until the remote peer receives and processes RST_STREAM or the frame bearing the END_STREAM flag, it might send frames of these types. Endpoints MUST ignore WINDOW_UPDATE or RST_STREAM frames received in this state, though endpoints MAY choose to treat frames that arrive a significant time after sending END_STREAM as a connection error of type PROTOCOL_ERROR. PRIORITY frames can be sent on closed streams to prioritize streams that are dependent on the closed stream. Endpoints SHOULD process PRIORITY frame, though they can be ignored if the stream has been removed from the dependency tree (see ). If this state is reached as a result of sending a RST_STREAM frame, the peer that receives the RST_STREAM might have already sent - or enqueued for sending - frames on the stream that cannot be withdrawn. An endpoint MUST ignore frames that it receives on closed streams after it has sent a RST_STREAM frame. An endpoint MAY choose to limit the period over which it ignores frames and treat frames that arrive after this time as being in error. Flow controlled frames (i.e., DATA) received after sending RST_STREAM are counted toward the connection flow control window. Even though these frames might be ignored, because they are sent before the sender receives the RST_STREAM, the sender will consider the frames to count against the flow control window. An endpoint might receive a PUSH_PROMISE frame after it sends RST_STREAM. PUSH_PROMISE causes a stream to become "reserved" even if the associated stream has been reset. Therefore, a RST_STREAM is needed to close an unwanted promised stream. In the absence of more specific guidance elsewhere in this document, implementations SHOULD treat the receipt of a frame that is not expressly permitted in the description of a state as a connection error of type PROTOCOL_ERROR. Frame of unknown types are ignored. An example of the state transitions for an HTTP request/response exchange can be found in . An example of the state transitions for server push can be found in and .
    Streams are identified with an unsigned 31-bit integer. Streams initiated by a client MUST use odd-numbered stream identifiers; those initiated by the server MUST use even-numbered stream identifiers. A stream identifier of zero (0x0) is used for connection control messages; the stream identifier zero cannot be used to establish a new stream. HTTP/1.1 requests that are upgraded to HTTP/2 (see ) are responded to with a stream identifier of one (0x1). After the upgrade completes, stream 0x1 is "half closed (local)" to the client. Therefore, stream 0x1 cannot be selected as a new stream identifier by a client that upgrades from HTTP/1.1. The identifier of a newly established stream MUST be numerically greater than all streams that the initiating endpoint has opened or reserved. This governs streams that are opened using a HEADERS frame and streams that are reserved using PUSH_PROMISE. An endpoint that receives an unexpected stream identifier MUST respond with a connection error of type PROTOCOL_ERROR. The first use of a new stream identifier implicitly closes all streams in the "idle" state that might have been initiated by that peer with a lower-valued stream identifier. For example, if a client sends a HEADERS frame on stream 7 without ever sending a frame on stream 5, then stream 5 transitions to the "closed" state when the first frame for stream 7 is sent or received. Stream identifiers cannot be reused. Long-lived connections can result in an endpoint exhausting the available range of stream identifiers. A client that is unable to establish a new stream identifier can establish a new connection for new streams. A server that is unable to establish a new stream identifier can send a GOAWAY frame so that the client is forced to open a new connection for new streams.
    A peer can limit the number of concurrently active streams using the SETTINGS_MAX_CONCURRENT_STREAMS parameter (see ) within a SETTINGS frame. The maximum concurrent streams setting is specific to each endpoint and applies only to the peer that receives the setting. That is, clients specify the maximum number of concurrent streams the server can initiate, and servers specify the maximum number of concurrent streams the client can initiate. Streams that are in the "open" state, or either of the "half closed" states count toward the maximum number of streams that an endpoint is permitted to open. Streams in any of these three states count toward the limit advertised in the SETTINGS_MAX_CONCURRENT_STREAMS setting. Streams in either of the "reserved" states do not count toward the stream limit. Endpoints MUST NOT exceed the limit set by their peer. An endpoint that receives a HEADERS frame that causes their advertised concurrent stream limit to be exceeded MUST treat this as a stream error. An endpoint that wishes to reduce the value of SETTINGS_MAX_CONCURRENT_STREAMS to a value that is below the current number of open streams can either close streams that exceed the new value or allow streams to complete.
    Using streams for multiplexing introduces contention over use of the TCP connection, resulting in blocked streams. A flow control scheme ensures that streams on the same connection do not destructively interfere with each other. Flow control is used for both individual streams and for the connection as a whole. HTTP/2 provides for flow control through use of the WINDOW_UPDATE frame.
    HTTP/2 stream flow control aims to allow a variety of flow control algorithms to be used without requiring protocol changes. Flow control in HTTP/2 has the following characteristics: Flow control is specific to a connection; i.e., it is "hop-by-hop", not "end-to-end". Flow control is based on window update frames. Receivers advertise how many octets they are prepared to receive on a stream and for the entire connection. This is a credit-based scheme. Flow control is directional with overall control provided by the receiver. A receiver MAY choose to set any window size that it desires for each stream and for the entire connection. A sender MUST respect flow control limits imposed by a receiver. Clients, servers and intermediaries all independently advertise their flow control window as a receiver and abide by the flow control limits set by their peer when sending. The initial value for the flow control window is 65,535 octets for both new streams and the overall connection. The frame type determines whether flow control applies to a frame. Of the frames specified in this document, only DATA frames are subject to flow control; all other frame types do not consume space in the advertised flow control window. This ensures that important control frames are not blocked by flow control. Flow control cannot be disabled. HTTP/2 defines only the format and semantics of the WINDOW_UPDATE frame (). This document does not stipulate how a receiver decides when to send this frame or the value that it sends, nor does it specify how a sender chooses to send packets. Implementations are able to select any algorithm that suits their needs. Implementations are also responsible for managing how requests and responses are sent based on priority; choosing how to avoid head of line blocking for requests; and managing the creation of new streams. Algorithm choices for these could interact with any flow control algorithm.
    Flow control is defined to protect endpoints that are operating under resource constraints. For example, a proxy needs to share memory between many connections, and also might have a slow upstream connection and a fast downstream one. Flow control addresses cases where the receiver is unable process data on one stream, yet wants to continue to process other streams in the same connection. Deployments that do not require this capability can advertise a flow control window of the maximum size, incrementing the available space when new data is received. This effectively disables flow control for that receiver. Conversely, a sender is always subject to the flow control window advertised by the receiver. Deployments with constrained resources (for example, memory) can employ flow control to limit the amount of memory a peer can consume. Note, however, that this can lead to suboptimal use of available network resources if flow control is enabled without knowledge of the bandwidth-delay product (see ). Even with full awareness of the current bandwidth-delay product, implementation of flow control can be difficult. When using flow control, the receiver MUST read from the TCP receive buffer in a timely fashion. Failure to do so could lead to a deadlock when critical frames, such as WINDOW_UPDATE, are not read and acted upon.
    A client can assign a priority for a new stream by including prioritization information in the HEADERS frame that opens the stream. For an existing stream, the PRIORITY frame can be used to change the priority. The purpose of prioritization is to allow an endpoint to express how it would prefer its peer allocate resources when managing concurrent streams. Most importantly, priority can be used to select streams for transmitting frames when there is limited capacity for sending. Streams can be prioritized by marking them as dependent on the completion of other streams (). Each dependency is assigned a relative weight, a number that is used to determine the relative proportion of available resources that are assigned to streams dependent on the same stream. Explicitly setting the priority for a stream is input to a prioritization process. It does not guarantee any particular processing or transmission order for the stream relative to any other stream. An endpoint cannot force a peer to process concurrent streams in a particular order using priority. Expressing priority is therefore only ever a suggestion. Providing prioritization information is optional, so default values are used if no explicit indicator is provided ().
    Each stream can be given an explicit dependency on another stream. Including a dependency expresses a preference to allocate resources to the identified stream rather than to the dependent stream. A stream that is not dependent on any other stream is given a stream dependency of 0x0. In other words, the non-existent stream 0 forms the root of the tree. A stream that depends on another stream is a dependent stream. The stream upon which a stream is dependent is a parent stream. A dependency on a stream that is not currently in the tree - such as a stream in the "idle" state - results in that stream being given a default priority. When assigning a dependency on another stream, the stream is added as a new dependency of the parent stream. Dependent streams that share the same parent are not ordered with respect to each other. For example, if streams B and C are dependent on stream A, and if stream D is created with a dependency on stream A, this results in a dependency order of A followed by B, C, and D in any order.
    /|\ B C B D C ]]>
    An exclusive flag allows for the insertion of a new level of dependencies. The exclusive flag causes the stream to become the sole dependency of its parent stream, causing other dependencies to become dependent on the exclusive stream. In the previous example, if stream D is created with an exclusive dependency on stream A, this results in D becoming the dependency parent of B and C.
    D B C / \ B C ]]>
    Inside the dependency tree, a dependent stream SHOULD only be allocated resources if all of the streams that it depends on (the chain of parent streams up to 0x0) are either closed, or it is not possible to make progress on them. A stream cannot depend on itself. An endpoint MUST treat this as a stream error of type PROTOCOL_ERROR.
    All dependent streams are allocated an integer weight between 1 and 256 (inclusive). Streams with the same parent SHOULD be allocated resources proportionally based on their weight. Thus, if stream B depends on stream A with weight 4, and C depends on stream A with weight 12, and if no progress can be made on A, stream B ideally receives one third of the resources allocated to stream C.
    Stream priorities are changed using the PRIORITY frame. Setting a dependency causes a stream to become dependent on the identified parent stream. Dependent streams move with their parent stream if the parent is reprioritized. Setting a dependency with the exclusive flag for a reprioritized stream moves all the dependencies of the new parent stream to become dependent on the reprioritized stream. If a stream is made dependent on one of its own dependencies, the formerly dependent stream is first moved to be dependent on the reprioritized stream's previous parent. The moved dependency retains its weight.
    For example, consider an original dependency tree where B and C depend on A, D and E depend on C, and F depends on D. If A is made dependent on D, then D takes the place of A. All other dependency relationships stay the same, except for F, which becomes dependent on A if the reprioritization is exclusive. F B C ==> F A OR A / \ | / \ /|\ D E E B C B C F | | | F E E (intermediate) (non-exclusive) (exclusive) ]]>
    When a stream is removed from the dependency tree, its dependencies can be moved to become dependent on the parent of the closed stream. The weights of new dependencies are recalculated by distributing the weight of the dependency of the closed stream proportionally based on the weights of its dependencies. Streams that are removed from the dependency tree cause some prioritization information to be lost. Resources are shared between streams with the same parent stream, which means that if a stream in that set closes or becomes blocked, any spare capacity allocated to a stream is distributed to the immediate neighbors of the stream. However, if the common dependency is removed from the tree, those streams share resources with streams at the next highest level. For example, assume streams A and B share a parent, and streams C and D both depend on stream A. Prior to the removal of stream A, if streams A and D are unable to proceed, then stream C receives all the resources dedicated to stream A. If stream A is removed from the tree, the weight of stream A is divided between streams C and D. If stream D is still unable to proceed, this results in stream C receiving a reduced proportion of resources. For equal starting weights, C receives one third, rather than one half, of available resources. It is possible for a stream to become closed while prioritization information that creates a dependency on that stream is in transit. If a stream identified in a dependency has no associated priority information, then the dependent stream is instead assigned a default priority. This potentially creates suboptimal prioritization, since the stream could be given a priority that is different to what is intended. To avoid these problems, an endpoint SHOULD retain stream prioritization state for a period after streams become closed. The longer state is retained, the lower the chance that streams are assigned incorrect or default priority values. This could create a large state burden for an endpoint, so this state MAY be limited. An endpoint MAY apply a fixed upper limit on the number of closed streams for which prioritization state is tracked to limit state exposure. The amount of additional state an endpoint maintains could be dependent on load; under high load, prioritization state can be discarded to limit resource commitments. In extreme cases, an endpoint could even discard prioritization state for active or reserved streams. If a fixed limit is applied, endpoints SHOULD maintain state for at least as many streams as allowed by their setting for SETTINGS_MAX_CONCURRENT_STREAMS. An endpoint receiving a PRIORITY frame that changes the priority of a closed stream SHOULD alter the dependencies of the streams that depend on it, if it has retained enough state to do so.
    Providing priority information is optional. Streams are assigned a non-exclusive dependency on stream 0x0 by default. Pushed streams initially depend on their associated stream. In both cases, streams are assigned a default weight of 16.
    HTTP/2 framing permits two classes of error: An error condition that renders the entire connection unusable is a connection error. An error in an individual stream is a stream error. A list of error codes is included in .
    A connection error is any error which prevents further processing of the framing layer, or which corrupts any connection state. An endpoint that encounters a connection error SHOULD first send a GOAWAY frame () with the stream identifier of the last stream that it successfully received from its peer. The GOAWAY frame includes an error code that indicates why the connection is terminating. After sending the GOAWAY frame, the endpoint MUST close the TCP connection. It is possible that the GOAWAY will not be reliably received by the receiving endpoint (see ). In the event of a connection error, GOAWAY only provides a best effort attempt to communicate with the peer about why the connection is being terminated. An endpoint can end a connection at any time. In particular, an endpoint MAY choose to treat a stream error as a connection error. Endpoints SHOULD send a GOAWAY frame when ending a connection, providing that circumstances permit it.
    A stream error is an error related to a specific stream that does not affect processing of other streams. An endpoint that detects a stream error sends a RST_STREAM frame () that contains the stream identifier of the stream where the error occurred. The RST_STREAM frame includes an error code that indicates the type of error. A RST_STREAM is the last frame that an endpoint can send on a stream. The peer that sends the RST_STREAM frame MUST be prepared to receive any frames that were sent or enqueued for sending by the remote peer. These frames can be ignored, except where they modify connection state (such as the state maintained for header compression, or flow control). Normally, an endpoint SHOULD NOT send more than one RST_STREAM frame for any stream. However, an endpoint MAY send additional RST_STREAM frames if it receives frames on a closed stream after more than a round-trip time. This behavior is permitted to deal with misbehaving implementations. An endpoint MUST NOT send a RST_STREAM in response to an RST_STREAM frame, to avoid looping.
    If the TCP connection is closed or reset while streams remain in open or half closed states, then the endpoint MUST assume that those streams were abnormally interrupted and could be incomplete.
    HTTP/2 permits extension of the protocol. Protocol extensions can be used to provide additional services or alter any aspect of the protocol, within the limitations described in this section. Extensions are effective only within the scope of a single HTTP/2 connection. Extensions are permitted to use new frame types, new settings, or new error codes. Registries are established for managing these extension points: frame types, settings and error codes. Implementations MUST ignore unknown or unsupported values in all extensible protocol elements. Implementations MUST discard frames that have unknown or unsupported types. This means that any of these extension points can be safely used by extensions without prior arrangement or negotiation. However, extension frames that appear in the middle of a header block are not permitted; these MUST be treated as a connection error of type PROTOCOL_ERROR. However, extensions that could change the semantics of existing protocol components MUST be negotiated before being used. For example, an extension that changes the layout of the HEADERS frame cannot be used until the peer has given a positive signal that this is acceptable. In this case, it could also be necessary to coordinate when the revised layout comes into effect. Note that treating any frame other than DATA frames as flow controlled is such a change in semantics, and can only be done through negotiation. This document doesn't mandate a specific method for negotiating the use of an extension, but notes that a setting could be used for that purpose. If both peers set a value that indicates willingness to use the extension, then the extension can be used. If a setting is used for extension negotiation, the initial value MUST be defined so that the extension is initially disabled.
    This specification defines a number of frame types, each identified by a unique 8-bit type code. Each frame type serves a distinct purpose either in the establishment and management of the connection as a whole, or of individual streams. The transmission of specific frame types can alter the state of a connection. If endpoints fail to maintain a synchronized view of the connection state, successful communication within the connection will no longer be possible. Therefore, it is important that endpoints have a shared comprehension of how the state is affected by the use any given frame.
    DATA frames (type=0x0) convey arbitrary, variable-length sequences of octets associated with a stream. One or more DATA frames are used, for instance, to carry HTTP request or response payloads. DATA frames MAY also contain arbitrary padding. Padding can be added to DATA frames to obscure the size of messages.
    The DATA frame contains the following fields: An 8-bit field containing the length of the frame padding in units of octets. This field is optional and is only present if the PADDED flag is set. Application data. The amount of data is the remainder of the frame payload after subtracting the length of the other fields that are present. Padding octets that contain no application semantic value. Padding octets MUST be set to zero when sending and ignored when receiving. The DATA frame defines the following flags: Bit 1 being set indicates that this frame is the last that the endpoint will send for the identified stream. Setting this flag causes the stream to enter one of the "half closed" states or the "closed" state. Bit 4 being set indicates that the Pad Length field and any padding that it describes is present. DATA frames MUST be associated with a stream. If a DATA frame is received whose stream identifier field is 0x0, the recipient MUST respond with a connection error of type PROTOCOL_ERROR. DATA frames are subject to flow control and can only be sent when a stream is in the "open" or "half closed (remote)" states. The entire DATA frame payload is included in flow control, including Pad Length and Padding fields if present. If a DATA frame is received whose stream is not in "open" or "half closed (local)" state, the recipient MUST respond with a stream error of type STREAM_CLOSED. The total number of padding octets is determined by the value of the Pad Length field. If the length of the padding is greater than the length of the frame payload, the recipient MUST treat this as a connection error of type PROTOCOL_ERROR. A frame can be increased in size by one octet by including a Pad Length field with a value of zero. Padding is a security feature; see .
    The HEADERS frame (type=0x1) is used to open a stream, and additionally carries a header block fragment. HEADERS frames can be sent on a stream in the "open" or "half closed (remote)" states.
    The HEADERS frame payload has the following fields: An 8-bit field containing the length of the frame padding in units of octets. This field is only present if the PADDED flag is set. A single bit flag indicates that the stream dependency is exclusive, see . This field is only present if the PRIORITY flag is set. A 31-bit stream identifier for the stream that this stream depends on, see . This field is only present if the PRIORITY flag is set. An 8-bit weight for the stream, see . Add one to the value to obtain a weight between 1 and 256. This field is only present if the PRIORITY flag is set. A header block fragment. Padding octets that contain no application semantic value. Padding octets MUST be set to zero when sending and ignored when receiving. The HEADERS frame defines the following flags: Bit 1 being set indicates that the header block is the last that the endpoint will send for the identified stream. Setting this flag causes the stream to enter one of "half closed" states. A HEADERS frame carries the END_STREAM flag that signals the end of a stream. However, a HEADERS frame with the END_STREAM flag set can be followed by CONTINUATION frames on the same stream. Logically, the CONTINUATION frames are part of the HEADERS frame. Bit 3 being set indicates that this frame contains an entire header block and is not followed by any CONTINUATION frames. A HEADERS frame without the END_HEADERS flag set MUST be followed by a CONTINUATION frame for the same stream. A receiver MUST treat the receipt of any other type of frame or a frame on a different stream as a connection error of type PROTOCOL_ERROR. Bit 4 being set indicates that the Pad Length field and any padding that it describes is present. Bit 6 being set indicates that the Exclusive Flag (E), Stream Dependency, and Weight fields are present; see . The payload of a HEADERS frame contains a header block fragment. A header block that does not fit within a HEADERS frame is continued in a CONTINUATION frame. HEADERS frames MUST be associated with a stream. If a HEADERS frame is received whose stream identifier field is 0x0, the recipient MUST respond with a connection error of type PROTOCOL_ERROR. The HEADERS frame changes the connection state as described in . The HEADERS frame includes optional padding. Padding fields and flags are identical to those defined for DATA frames. Prioritization information in a HEADERS frame is logically equivalent to a separate PRIORITY frame, but inclusion in HEADERS avoids the potential for churn in stream prioritization when new streams are created. Priorization fields in HEADERS frames subsequent to the first on a stream reprioritize the stream.
    The PRIORITY frame (type=0x2) specifies the sender-advised priority of a stream. It can be sent at any time for an existing stream, including closed streams. This enables reprioritization of existing streams.
    The payload of a PRIORITY frame contains the following fields: A single bit flag indicates that the stream dependency is exclusive, see . A 31-bit stream identifier for the stream that this stream depends on, see . An 8-bit weight for the identified stream dependency, see . Add one to the value to obtain a weight between 1 and 256. The PRIORITY frame does not define any flags. The PRIORITY frame is associated with an existing stream. If a PRIORITY frame is received with a stream identifier of 0x0, the recipient MUST respond with a connection error of type PROTOCOL_ERROR. The PRIORITY frame can be sent on a stream in any of the "reserved (remote)", "open", "half closed (local)", "half closed (remote)", or "closed" states, though it cannot be sent between consecutive frames that comprise a single header block. Note that this frame could arrive after processing or frame sending has completed, which would cause it to have no effect on the current stream. For a stream that is in the "half closed (remote)" or "closed" - state, this frame can only affect processing of the current stream and not frame transmission. The PRIORITY frame is the only frame that can be sent for a stream in the "closed" state. This allows for the reprioritization of a group of dependent streams by altering the priority of a parent stream, which might be closed. However, a PRIORITY frame sent on a closed stream risks being ignored due to the peer having discarded priority state information for that stream.
    The RST_STREAM frame (type=0x3) allows for abnormal termination of a stream. When sent by the initiator of a stream, it indicates that they wish to cancel the stream or that an error condition has occurred. When sent by the receiver of a stream, it indicates that either the receiver is rejecting the stream, requesting that the stream be cancelled, or that an error condition has occurred.
    The RST_STREAM frame contains a single unsigned, 32-bit integer identifying the error code. The error code indicates why the stream is being terminated. The RST_STREAM frame does not define any flags. The RST_STREAM frame fully terminates the referenced stream and causes it to enter the closed state. After receiving a RST_STREAM on a stream, the receiver MUST NOT send additional frames for that stream, with the exception of PRIORITY. However, after sending the RST_STREAM, the sending endpoint MUST be prepared to receive and process additional frames sent on the stream that might have been sent by the peer prior to the arrival of the RST_STREAM. RST_STREAM frames MUST be associated with a stream. If a RST_STREAM frame is received with a stream identifier of 0x0, the recipient MUST treat this as a connection error of type PROTOCOL_ERROR. RST_STREAM frames MUST NOT be sent for a stream in the "idle" state. If a RST_STREAM frame identifying an idle stream is received, the recipient MUST treat this as a connection error of type PROTOCOL_ERROR.
    The SETTINGS frame (type=0x4) conveys configuration parameters that affect how endpoints communicate, such as preferences and constraints on peer behavior. The SETTINGS frame is also used to acknowledge the receipt of those parameters. Individually, a SETTINGS parameter can also be referred to as a "setting". SETTINGS parameters are not negotiated; they describe characteristics of the sending peer, which are used by the receiving peer. Different values for the same parameter can be advertised by each peer. For example, a client might set a high initial flow control window, whereas a server might set a lower value to conserve resources. A SETTINGS frame MUST be sent by both endpoints at the start of a connection, and MAY be sent at any other time by either endpoint over the lifetime of the connection. Implementations MUST support all of the parameters defined by this specification. Each parameter in a SETTINGS frame replaces any existing value for that parameter. Parameters are processed in the order in which they appear, and a receiver of a SETTINGS frame does not need to maintain any state other than the current value of its parameters. Therefore, the value of a SETTINGS parameter is the last value that is seen by a receiver. SETTINGS parameters are acknowledged by the receiving peer. To enable this, the SETTINGS frame defines the following flag: Bit 1 being set indicates that this frame acknowledges receipt and application of the peer's SETTINGS frame. When this bit is set, the payload of the SETTINGS frame MUST be empty. Receipt of a SETTINGS frame with the ACK flag set and a length field value other than 0 MUST be treated as a connection error of type FRAME_SIZE_ERROR. For more info, see Settings Synchronization. SETTINGS frames always apply to a connection, never a single stream. The stream identifier for a SETTINGS frame MUST be zero (0x0). If an endpoint receives a SETTINGS frame whose stream identifier field is anything other than 0x0, the endpoint MUST respond with a connection error of type PROTOCOL_ERROR. The SETTINGS frame affects connection state. A badly formed or incomplete SETTINGS frame MUST be treated as a connection error of type PROTOCOL_ERROR.
    The payload of a SETTINGS frame consists of zero or more parameters, each consisting of an unsigned 16-bit setting identifier and an unsigned 32-bit value.
    The following parameters are defined: Allows the sender to inform the remote endpoint of the maximum size of the header compression table used to decode header blocks, in octets. The encoder can select any size equal to or less than this value by using signaling specific to the header compression format inside a header block. The initial value is 4,096 octets. This setting can be use to disable server push. An endpoint MUST NOT send a PUSH_PROMISE frame if it receives this parameter set to a value of 0. An endpoint that has both set this parameter to 0 and had it acknowledged MUST treat the receipt of a PUSH_PROMISE frame as a connection error of type PROTOCOL_ERROR. The initial value is 1, which indicates that server push is permitted. Any value other than 0 or 1 MUST be treated as a connection error of type PROTOCOL_ERROR. Indicates the maximum number of concurrent streams that the sender will allow. This limit is directional: it applies to the number of streams that the sender permits the receiver to create. Initially there is no limit to this value. It is recommended that this value be no smaller than 100, so as to not unnecessarily limit parallelism. A value of 0 for SETTINGS_MAX_CONCURRENT_STREAMS SHOULD NOT be treated as special by endpoints. A zero value does prevent the creation of new streams, however this can also happen for any limit that is exhausted with active streams. Servers SHOULD only set a zero value for short durations; if a server does not wish to accept requests, closing the connection could be preferable. Indicates the sender's initial window size (in octets) for stream level flow control. The initial value is 216-1 (65,535) octets. This setting affects the window size of all streams, including existing streams, see . Values above the maximum flow control window size of 231-1 MUST be treated as a connection error of type FLOW_CONTROL_ERROR. Indicates the size of the largest frame payload that the sender is willing to receive, in octets. The initial value is 214 (16,384) octets. The value advertised by an endpoint MUST be between this initial value and the maximum allowed frame size (224-1 or 16,777,215 octets), inclusive. Values outside this range MUST be treated as a connection error of type PROTOCOL_ERROR. This advisory setting informs a peer of the maximum size of header list that the sender is prepared to accept, in octets. The value is based on the uncompressed size of header fields, including the length of the name and value in octets plus an overhead of 32 octets for each header field. For any given request, a lower limit than what is advertised MAY be enforced. The initial value of this setting is unlimited. An endpoint that receives a SETTINGS frame with any unknown or unsupported identifier MUST ignore that setting.
    Most values in SETTINGS benefit from or require an understanding of when the peer has received and applied the changed parameter values. In order to provide such synchronization timepoints, the recipient of a SETTINGS frame in which the ACK flag is not set MUST apply the updated parameters as soon as possible upon receipt. The values in the SETTINGS frame MUST be processed in the order they appear, with no other frame processing between values. Unsupported parameters MUST be ignored. Once all values have been processed, the recipient MUST immediately emit a SETTINGS frame with the ACK flag set. Upon receiving a SETTINGS frame with the ACK flag set, the sender of the altered parameters can rely on the setting having been applied. If the sender of a SETTINGS frame does not receive an acknowledgement within a reasonable amount of time, it MAY issue a connection error of type SETTINGS_TIMEOUT.
    The PUSH_PROMISE frame (type=0x5) is used to notify the peer endpoint in advance of streams the sender intends to initiate. The PUSH_PROMISE frame includes the unsigned 31-bit identifier of the stream the endpoint plans to create along with a set of headers that provide additional context for the stream. contains a thorough description of the use of PUSH_PROMISE frames.
    The PUSH_PROMISE frame payload has the following fields: An 8-bit field containing the length of the frame padding in units of octets. This field is only present if the PADDED flag is set. A single reserved bit. An unsigned 31-bit integer that identifies the stream that is reserved by the PUSH_PROMISE. The promised stream identifier MUST be a valid choice for the next stream sent by the sender (see new stream identifier). A header block fragment containing request header fields. Padding octets. The PUSH_PROMISE frame defines the following flags: Bit 3 being set indicates that this frame contains an entire header block and is not followed by any CONTINUATION frames. A PUSH_PROMISE frame without the END_HEADERS flag set MUST be followed by a CONTINUATION frame for the same stream. A receiver MUST treat the receipt of any other type of frame or a frame on a different stream as a connection error of type PROTOCOL_ERROR. Bit 4 being set indicates that the Pad Length field and any padding that it describes is present. PUSH_PROMISE frames MUST be associated with an existing, peer-initiated stream. The stream identifier of a PUSH_PROMISE frame indicates the stream it is associated with. If the stream identifier field specifies the value 0x0, a recipient MUST respond with a connection error of type PROTOCOL_ERROR. Promised streams are not required to be used in the order they are promised. The PUSH_PROMISE only reserves stream identifiers for later use. PUSH_PROMISE MUST NOT be sent if the SETTINGS_ENABLE_PUSH setting of the peer endpoint is set to 0. An endpoint that has set this setting and has received acknowledgement MUST treat the receipt of a PUSH_PROMISE frame as a connection error of type PROTOCOL_ERROR. Recipients of PUSH_PROMISE frames can choose to reject promised streams by returning a RST_STREAM referencing the promised stream identifier back to the sender of the PUSH_PROMISE. A PUSH_PROMISE frame modifies the connection state in two ways. The inclusion of a header block potentially modifies the state maintained for header compression. PUSH_PROMISE also reserves a stream for later use, causing the promised stream to enter the "reserved" state. A sender MUST NOT send a PUSH_PROMISE on a stream unless that stream is either "open" or "half closed (remote)"; the sender MUST ensure that the promised stream is a valid choice for a new stream identifier (that is, the promised stream MUST be in the "idle" state). Since PUSH_PROMISE reserves a stream, ignoring a PUSH_PROMISE frame causes the stream state to become indeterminate. A receiver MUST treat the receipt of a PUSH_PROMISE on a stream that is neither "open" nor "half closed (local)" as a connection error of type PROTOCOL_ERROR. However, an endpoint that has sent RST_STREAM on the associated stream MUST handle PUSH_PROMISE frames that might have been created before the RST_STREAM frame is received and processed. A receiver MUST treat the receipt of a PUSH_PROMISE that promises an illegal stream identifier (that is, an identifier for a stream that is not currently in the "idle" state) as a connection error of type PROTOCOL_ERROR. The PUSH_PROMISE frame includes optional padding. Padding fields and flags are identical to those defined for DATA frames.
    The PING frame (type=0x6) is a mechanism for measuring a minimal round trip time from the sender, as well as determining whether an idle connection is still functional. PING frames can be sent from any endpoint.
    In addition to the frame header, PING frames MUST contain 8 octets of data in the payload. A sender can include any value it chooses and use those bytes in any fashion. Receivers of a PING frame that does not include an ACK flag MUST send a PING frame with the ACK flag set in response, with an identical payload. PING responses SHOULD be given higher priority than any other frame. The PING frame defines the following flags: Bit 1 being set indicates that this PING frame is a PING response. An endpoint MUST set this flag in PING responses. An endpoint MUST NOT respond to PING frames containing this flag. PING frames are not associated with any individual stream. If a PING frame is received with a stream identifier field value other than 0x0, the recipient MUST respond with a connection error of type PROTOCOL_ERROR. Receipt of a PING frame with a length field value other than 8 MUST be treated as a connection error of type FRAME_SIZE_ERROR.
    The GOAWAY frame (type=0x7) informs the remote peer to stop creating streams on this connection. GOAWAY can be sent by either the client or the server. Once sent, the sender will ignore frames sent on any new streams with identifiers higher than the included last stream identifier. Receivers of a GOAWAY frame MUST NOT open additional streams on the connection, although a new connection can be established for new streams. The purpose of this frame is to allow an endpoint to gracefully stop accepting new streams, while still finishing processing of previously established streams. This enables administrative actions, like server maintainance. There is an inherent race condition between an endpoint starting new streams and the remote sending a GOAWAY frame. To deal with this case, the GOAWAY contains the stream identifier of the last peer-initiated stream which was or might be processed on the sending endpoint in this connection. For instance, if the server sends a GOAWAY frame, the identified stream is the highest numbered stream initiated by the client. If the receiver of the GOAWAY has sent data on streams with a higher stream identifier than what is indicated in the GOAWAY frame, those streams are not or will not be processed. The receiver of the GOAWAY frame can treat the streams as though they had never been created at all, thereby allowing those streams to be retried later on a new connection. Endpoints SHOULD always send a GOAWAY frame before closing a connection so that the remote can know whether a stream has been partially processed or not. For example, if an HTTP client sends a POST at the same time that a server closes a connection, the client cannot know if the server started to process that POST request if the server does not send a GOAWAY frame to indicate what streams it might have acted on. An endpoint might choose to close a connection without sending GOAWAY for misbehaving peers.
    The GOAWAY frame does not define any flags. The GOAWAY frame applies to the connection, not a specific stream. An endpoint MUST treat a GOAWAY frame with a stream identifier other than 0x0 as a connection error of type PROTOCOL_ERROR. The last stream identifier in the GOAWAY frame contains the highest numbered stream identifier for which the sender of the GOAWAY frame might have taken some action on, or might yet take action on. All streams up to and including the identified stream might have been processed in some way. The last stream identifier can be set to 0 if no streams were processed. In this context, "processed" means that some data from the stream was passed to some higher layer of software that might have taken some action as a result. If a connection terminates without a GOAWAY frame, the last stream identifier is effectively the highest possible stream identifier. On streams with lower or equal numbered identifiers that were not closed completely prior to the connection being closed, re-attempting requests, transactions, or any protocol activity is not possible, with the exception of idempotent actions like HTTP GET, PUT, or DELETE. Any protocol activity that uses higher numbered streams can be safely retried using a new connection. Activity on streams numbered lower or equal to the last stream identifier might still complete successfully. The sender of a GOAWAY frame might gracefully shut down a connection by sending a GOAWAY frame, maintaining the connection in an open state until all in-progress streams complete. An endpoint MAY send multiple GOAWAY frames if circumstances change. For instance, an endpoint that sends GOAWAY with NO_ERROR during graceful shutdown could subsequently encounter an condition that requires immediate termination of the connection. The last stream identifier from the last GOAWAY frame received indicates which streams could have been acted upon. Endpoints MUST NOT increase the value they send in the last stream identifier, since the peers might already have retried unprocessed requests on another connection. A client that is unable to retry requests loses all requests that are in flight when the server closes the connection. This is especially true for intermediaries that might not be serving clients using HTTP/2. A server that is attempting to gracefully shut down a connection SHOULD send an initial GOAWAY frame with the last stream identifier set to 231-1 and a NO_ERROR code. This signals to the client that a shutdown is imminent and that no further requests can be initiated. After waiting at least one round trip time, the server can send another GOAWAY frame with an updated last stream identifier. This ensures that a connection can be cleanly shut down without losing requests. After sending a GOAWAY frame, the sender can discard frames for streams with identifiers higher than the identified last stream. However, any frames that alter connection state cannot be completely ignored. For instance, HEADERS, PUSH_PROMISE and CONTINUATION frames MUST be minimally processed to ensure the state maintained for header compression is consistent (see ); similarly DATA frames MUST be counted toward the connection flow control window. Failure to process these frames can cause flow control or header compression state to become unsynchronized. The GOAWAY frame also contains a 32-bit error code that contains the reason for closing the connection. Endpoints MAY append opaque data to the payload of any GOAWAY frame. Additional debug data is intended for diagnostic purposes only and carries no semantic value. Debug information could contain security- or privacy-sensitive data. Logged or otherwise persistently stored debug data MUST have adequate safeguards to prevent unauthorized access.
    The WINDOW_UPDATE frame (type=0x8) is used to implement flow control; see for an overview. Flow control operates at two levels: on each individual stream and on the entire connection. Both types of flow control are hop-by-hop; that is, only between the two endpoints. Intermediaries do not forward WINDOW_UPDATE frames between dependent connections. However, throttling of data transfer by any receiver can indirectly cause the propagation of flow control information toward the original sender. Flow control only applies to frames that are identified as being subject to flow control. Of the frame types defined in this document, this includes only DATA frames. Frames that are exempt from flow control MUST be accepted and processed, unless the receiver is unable to assign resources to handling the frame. A receiver MAY respond with a stream error or connection error of type FLOW_CONTROL_ERROR if it is unable to accept a frame.
    The payload of a WINDOW_UPDATE frame is one reserved bit, plus an unsigned 31-bit integer indicating the number of octets that the sender can transmit in addition to the existing flow control window. The legal range for the increment to the flow control window is 1 to 231-1 (0x7fffffff) octets. The WINDOW_UPDATE frame does not define any flags. The WINDOW_UPDATE frame can be specific to a stream or to the entire connection. In the former case, the frame's stream identifier indicates the affected stream; in the latter, the value "0" indicates that the entire connection is the subject of the frame. A receiver MUST treat the receipt of a WINDOW_UPDATE frame with an flow control window increment of 0 as a stream error of type PROTOCOL_ERROR; errors on the connection flow control window MUST be treated as a connection error. WINDOW_UPDATE can be sent by a peer that has sent a frame bearing the END_STREAM flag. This means that a receiver could receive a WINDOW_UPDATE frame on a "half closed (remote)" or "closed" stream. A receiver MUST NOT treat this as an error, see . A receiver that receives a flow controlled frame MUST always account for its contribution against the connection flow control window, unless the receiver treats this as a connection error. This is necessary even if the frame is in error. Since the sender counts the frame toward the flow control window, if the receiver does not, the flow control window at sender and receiver can become different.
    Flow control in HTTP/2 is implemented using a window kept by each sender on every stream. The flow control window is a simple integer value that indicates how many octets of data the sender is permitted to transmit; as such, its size is a measure of the buffering capacity of the receiver. Two flow control windows are applicable: the stream flow control window and the connection flow control window. The sender MUST NOT send a flow controlled frame with a length that exceeds the space available in either of the flow control windows advertised by the receiver. Frames with zero length with the END_STREAM flag set (that is, an empty DATA frame) MAY be sent if there is no available space in either flow control window. For flow control calculations, the 9 octet frame header is not counted. After sending a flow controlled frame, the sender reduces the space available in both windows by the length of the transmitted frame. The receiver of a frame sends a WINDOW_UPDATE frame as it consumes data and frees up space in flow control windows. Separate WINDOW_UPDATE frames are sent for the stream and connection level flow control windows. A sender that receives a WINDOW_UPDATE frame updates the corresponding window by the amount specified in the frame. A sender MUST NOT allow a flow control window to exceed 231-1 octets. If a sender receives a WINDOW_UPDATE that causes a flow control window to exceed this maximum it MUST terminate either the stream or the connection, as appropriate. For streams, the sender sends a RST_STREAM with the error code of FLOW_CONTROL_ERROR code; for the connection, a GOAWAY frame with a FLOW_CONTROL_ERROR code. Flow controlled frames from the sender and WINDOW_UPDATE frames from the receiver are completely asynchronous with respect to each other. This property allows a receiver to aggressively update the window size kept by the sender to prevent streams from stalling.
    When an HTTP/2 connection is first established, new streams are created with an initial flow control window size of 65,535 octets. The connection flow control window is 65,535 octets. Both endpoints can adjust the initial window size for new streams by including a value for SETTINGS_INITIAL_WINDOW_SIZE in the SETTINGS frame that forms part of the connection preface. The connection flow control window can only be changed using WINDOW_UPDATE frames. Prior to receiving a SETTINGS frame that sets a value for SETTINGS_INITIAL_WINDOW_SIZE, an endpoint can only use the default initial window size when sending flow controlled frames. Similarly, the connection flow control window is set to the default initial window size until a WINDOW_UPDATE frame is received. A SETTINGS frame can alter the initial flow control window size for all current streams. When the value of SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver MUST adjust the size of all stream flow control windows that it maintains by the difference between the new value and the old value. A change to SETTINGS_INITIAL_WINDOW_SIZE can cause the available space in a flow control window to become negative. A sender MUST track the negative flow control window, and MUST NOT send new flow controlled frames until it receives WINDOW_UPDATE frames that cause the flow control window to become positive. For example, if the client sends 60KB immediately on connection establishment, and the server sets the initial window size to be 16KB, the client will recalculate the available flow control window to be -44KB on receipt of the SETTINGS frame. The client retains a negative flow control window until WINDOW_UPDATE frames restore the window to being positive, after which the client can resume sending. A SETTINGS frame cannot alter the connection flow control window. An endpoint MUST treat a change to SETTINGS_INITIAL_WINDOW_SIZE that causes any flow control window to exceed the maximum size as a connection error of type FLOW_CONTROL_ERROR.
    A receiver that wishes to use a smaller flow control window than the current size can send a new SETTINGS frame. However, the receiver MUST be prepared to receive data that exceeds this window size, since the sender might send data that exceeds the lower limit prior to processing the SETTINGS frame. After sending a SETTINGS frame that reduces the initial flow control window size, a receiver has two options for handling streams that exceed flow control limits: The receiver can immediately send RST_STREAM with FLOW_CONTROL_ERROR error code for the affected streams. The receiver can accept the streams and tolerate the resulting head of line blocking, sending WINDOW_UPDATE frames as it consumes data.
    The CONTINUATION frame (type=0x9) is used to continue a sequence of header block fragments. Any number of CONTINUATION frames can be sent on an existing stream, as long as the preceding frame is on the same stream and is a HEADERS, PUSH_PROMISE or CONTINUATION frame without the END_HEADERS flag set.
    The CONTINUATION frame payload contains a header block fragment. The CONTINUATION frame defines the following flag: Bit 3 being set indicates that this frame ends a header block. If the END_HEADERS bit is not set, this frame MUST be followed by another CONTINUATION frame. A receiver MUST treat the receipt of any other type of frame or a frame on a different stream as a connection error of type PROTOCOL_ERROR. The CONTINUATION frame changes the connection state as defined in . CONTINUATION frames MUST be associated with a stream. If a CONTINUATION frame is received whose stream identifier field is 0x0, the recipient MUST respond with a connection error of type PROTOCOL_ERROR. A CONTINUATION frame MUST be preceded by a HEADERS, PUSH_PROMISE or CONTINUATION frame without the END_HEADERS flag set. A recipient that observes violation of this rule MUST respond with a connection error of type PROTOCOL_ERROR.
    Error codes are 32-bit fields that are used in RST_STREAM and GOAWAY frames to convey the reasons for the stream or connection error. Error codes share a common code space. Some error codes apply only to either streams or the entire connection and have no defined semantics in the other context. The following error codes are defined: The associated condition is not as a result of an error. For example, a GOAWAY might include this code to indicate graceful shutdown of a connection. The endpoint detected an unspecific protocol error. This error is for use when a more specific error code is not available. The endpoint encountered an unexpected internal error. The endpoint detected that its peer violated the flow control protocol. The endpoint sent a SETTINGS frame, but did not receive a response in a timely manner. See Settings Synchronization. The endpoint received a frame after a stream was half closed. The endpoint received a frame with an invalid size. The endpoint refuses the stream prior to performing any application processing, see for details. Used by the endpoint to indicate that the stream is no longer needed. The endpoint is unable to maintain the header compression context for the connection. The connection established in response to a CONNECT request was reset or abnormally closed. The endpoint detected that its peer is exhibiting a behavior that might be generating excessive load. The underlying transport has properties that do not meet minimum security requirements (see ). Unknown or unsupported error codes MUST NOT trigger any special behavior. These MAY be treated by an implementation as being equivalent to INTERNAL_ERROR.
    HTTP/2 is intended to be as compatible as possible with current uses of HTTP. This means that, from the application perspective, the features of the protocol are largely unchanged. To achieve this, all request and response semantics are preserved, although the syntax of conveying those semantics has changed. Thus, the specification and requirements of HTTP/1.1 Semantics and Content , Conditional Requests , Range Requests , Caching and Authentication are applicable to HTTP/2. Selected portions of HTTP/1.1 Message Syntax and Routing , such as the HTTP and HTTPS URI schemes, are also applicable in HTTP/2, but the expression of those semantics for this protocol are defined in the sections below.
    A client sends an HTTP request on a new stream, using a previously unused stream identifier. A server sends an HTTP response on the same stream as the request. An HTTP message (request or response) consists of: for a response only, zero or more HEADERS frames (each followed by zero or more CONTINUATION frames) containing the message headers of informational (1xx) HTTP responses (see and ), and one HEADERS frame (followed by zero or more CONTINUATION frames) containing the message headers (see ), and zero or more DATA frames containing the message payload (see ), and optionally, one HEADERS frame, followed by zero or more CONTINUATION frames containing the trailer-part, if present (see ). The last frame in the sequence bears an END_STREAM flag, noting that a HEADERS frame bearing the END_STREAM flag can be followed by CONTINUATION frames that carry any remaining portions of the header block. Other frames (from any stream) MUST NOT occur between either HEADERS frame and any CONTINUATION frames that might follow. Trailing header fields are carried in a header block that also terminates the stream. That is, a sequence starting with a HEADERS frame, followed by zero or more CONTINUATION frames, where the HEADERS frame bears an END_STREAM flag. Header blocks after the first that do not terminate the stream are not part of an HTTP request or response. A HEADERS frame (and associated CONTINUATION frames) can only appear at the start or end of a stream. An endpoint that receives a HEADERS frame without the END_STREAM flag set after receiving a final (non-informational) status code MUST treat the corresponding request or response as malformed. An HTTP request/response exchange fully consumes a single stream. A request starts with the HEADERS frame that puts the stream into an "open" state. The request ends with a frame bearing END_STREAM, which causes the stream to become "half closed (local)" for the client and "half closed (remote)" for the server. A response starts with a HEADERS frame and ends with a frame bearing END_STREAM, which places the stream in the "closed" state.
    HTTP/2 removes support for the 101 (Switching Protocols) informational status code (). The semantics of 101 (Switching Protocols) aren't applicable to a multiplexed protocol. Alternative protocols are able to use the same mechanisms that HTTP/2 uses to negotiate their use (see ).
    HTTP header fields carry information as a series of key-value pairs. For a listing of registered HTTP headers, see the Message Header Field Registry maintained at .
    While HTTP/1.x used the message start-line (see ) to convey the target URI and method of the request, and the status code for the response, HTTP/2 uses special pseudo-header fields beginning with ':' character (ASCII 0x3a) for this purpose. Pseudo-header fields are not HTTP header fields. Endpoints MUST NOT generate pseudo-header fields other than those defined in this document. Pseudo-header fields are only valid in the context in which they are defined. Pseudo-header fields defined for requests MUST NOT appear in responses; pseudo-header fields defined for responses MUST NOT appear in requests. Pseudo-header fields MUST NOT appear in trailers. Endpoints MUST treat a request or response that contains undefined or invalid pseudo-header fields as malformed. Just as in HTTP/1.x, header field names are strings of ASCII characters that are compared in a case-insensitive fashion. However, header field names MUST be converted to lowercase prior to their encoding in HTTP/2. A request or response containing uppercase header field names MUST be treated as malformed. All pseudo-header fields MUST appear in the header block before regular header fields. Any request or response that contains a pseudo-header field that appears in a header block after a regular header field MUST be treated as malformed.
    HTTP/2 does not use the Connection header field to indicate connection-specific header fields; in this protocol, connection-specific metadata is conveyed by other means. An endpoint MUST NOT generate a HTTP/2 message containing connection-specific header fields; any message containing connection-specific header fields MUST be treated as malformed. This means that an intermediary transforming an HTTP/1.x message to HTTP/2 will need to remove any header fields nominated by the Connection header field, along with the Connection header field itself. Such intermediaries SHOULD also remove other connection-specific header fields, such as Keep-Alive, Proxy-Connection, Transfer-Encoding and Upgrade, even if they are not nominated by Connection. One exception to this is the TE header field, which MAY be present in an HTTP/2 request, but when it is MUST NOT contain any value other than "trailers". HTTP/2 purposefully does not support upgrade to another protocol. The handshake methods described in are believed sufficient to negotiate the use of alternative protocols.
    The following pseudo-header fields are defined for HTTP/2 requests: The :method pseudo-header field includes the HTTP method (). The :scheme pseudo-header field includes the scheme portion of the target URI (). :scheme is not restricted to http and https schemed URIs. A proxy or gateway can translate requests for non-HTTP schemes, enabling the use of HTTP to interact with non-HTTP services. The :authority pseudo-header field includes the authority portion of the target URI (). The authority MUST NOT include the deprecated userinfo subcomponent for http or https schemed URIs. To ensure that the HTTP/1.1 request line can be reproduced accurately, this pseudo-header field MUST be omitted when translating from an HTTP/1.1 request that has a request target in origin or asterisk form (see ). Clients that generate HTTP/2 requests directly SHOULD use the :authority pseudo-header field instead of the Host header field. An intermediary that converts an HTTP/2 request to HTTP/1.1 MUST create a Host header field if one is not present in a request by copying the value of the :authority pseudo-header field. The :path pseudo-header field includes the path and query parts of the target URI (the path-absolute production from and optionally a '?' character followed by the query production, see and ). A request in asterisk form includes the value '*' for the :path pseudo-header field. This pseudo-header field MUST NOT be empty for http or https URIs; http or https URIs that do not contain a path component MUST include a value of '/'. The exception to this rule is an OPTIONS request for an http or https URI that does not include a path component; these MUST include a :path pseudo-header field with a value of '*' (see ). All HTTP/2 requests MUST include exactly one valid value for the :method, :scheme, and :path pseudo-header fields, unless it is a CONNECT request. An HTTP request that omits mandatory pseudo-header fields is malformed. HTTP/2 does not define a way to carry the version identifier that is included in the HTTP/1.1 request line.
    For HTTP/2 responses, a single :status pseudo-header field is defined that carries the HTTP status code field (see ). This pseudo-header field MUST be included in all responses, otherwise the response is malformed. HTTP/2 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status line.
    The Cookie header field can carry a significant amount of redundant data. The Cookie header field uses a semi-colon (";") to delimit cookie-pairs (or "crumbs"). This header field doesn't follow the list construction rules in HTTP (see ), which prevents cookie-pairs from being separated into different name-value pairs. This can significantly reduce compression efficiency as individual cookie-pairs are updated. To allow for better compression efficiency, the Cookie header field MAY be split into separate header fields, each with one or more cookie-pairs. If there are multiple Cookie header fields after decompression, these MUST be concatenated into a single octet string using the two octet delimiter of 0x3B, 0x20 (the ASCII string "; ") before being passed into a non-HTTP/2 context, such as an HTTP/1.1 connection, or a generic HTTP server application.
    Therefore, the following two lists of Cookie header fields are semantically equivalent.
    A malformed request or response is one that is an otherwise valid sequence of HTTP/2 frames, but is otherwise invalid due to the presence of extraneous frames, prohibited header fields, the absence of mandatory header fields, or the inclusion of uppercase header field names. A request or response that includes an entity body can include a content-length header field. A request or response is also malformed if the value of a content-length header field does not equal the sum of the DATA frame payload lengths that form the body. A response that is defined to have no payload, as described in , can have a non-zero content-length header field, even though no content is included in DATA frames. Intermediaries that process HTTP requests or responses (i.e., any intermediary not acting as a tunnel) MUST NOT forward a malformed request or response. Malformed requests or responses that are detected MUST be treated as a stream error of type PROTOCOL_ERROR. For malformed requests, a server MAY send an HTTP response prior to closing or resetting the stream. Clients MUST NOT accept a malformed response. Note that these requirements are intended to protect against several types of common attacks against HTTP; they are deliberately strict, because being permissive can expose implementations to these vulnerabilities.
    This section shows HTTP/1.1 requests and responses, with illustrations of equivalent HTTP/2 requests and responses. An HTTP GET request includes request header fields and no body and is therefore transmitted as a single HEADERS frame, followed by zero or more CONTINUATION frames containing the serialized block of request header fields. The HEADERS frame in the following has both the END_HEADERS and END_STREAM flags set; no CONTINUATION frames are sent:
    + END_STREAM Accept: image/jpeg + END_HEADERS :method = GET :scheme = https :path = /resource host = example.org accept = image/jpeg ]]>
    Similarly, a response that includes only response header fields is transmitted as a HEADERS frame (again, followed by zero or more CONTINUATION frames) containing the serialized block of response header fields.
    + END_STREAM Expires: Thu, 23 Jan ... + END_HEADERS :status = 304 etag = "xyzzy" expires = Thu, 23 Jan ... ]]>
    An HTTP POST request that includes request header fields and payload data is transmitted as one HEADERS frame, followed by zero or more CONTINUATION frames containing the request header fields, followed by one or more DATA frames, with the last CONTINUATION (or HEADERS) frame having the END_HEADERS flag set and the final DATA frame having the END_STREAM flag set:
    - END_STREAM Content-Type: image/jpeg - END_HEADERS Content-Length: 123 :method = POST :path = /resource {binary data} :scheme = https CONTINUATION + END_HEADERS content-type = image/jpeg host = example.org content-length = 123 DATA + END_STREAM {binary data} ]]> Note that data contributing to any given header field could be spread between header block fragments. The allocation of header fields to frames in this example is illustrative only.
    A response that includes header fields and payload data is transmitted as a HEADERS frame, followed by zero or more CONTINUATION frames, followed by one or more DATA frames, with the last DATA frame in the sequence having the END_STREAM flag set:
    - END_STREAM Content-Length: 123 + END_HEADERS :status = 200 {binary data} content-type = image/jpeg content-length = 123 DATA + END_STREAM {binary data} ]]>
    Trailing header fields are sent as a header block after both the request or response header block and all the DATA frames have been sent. The HEADERS frame starting the trailers header block has the END_STREAM flag set.
    - END_STREAM Transfer-Encoding: chunked + END_HEADERS Trailer: Foo :status = 200 content-length = 123 123 content-type = image/jpeg {binary data} trailer = Foo 0 Foo: bar DATA - END_STREAM {binary data} HEADERS + END_STREAM + END_HEADERS foo = bar ]]>
    An informational response using a 1xx status code other than 101 is transmitted as a HEADERS frame, followed by zero or more CONTINUATION frames: - END_STREAM + END_HEADERS :status = 103 extension-field = bar ]]>
    In HTTP/1.1, an HTTP client is unable to retry a non-idempotent request when an error occurs, because there is no means to determine the nature of the error. It is possible that some server processing occurred prior to the error, which could result in undesirable effects if the request were reattempted. HTTP/2 provides two mechanisms for providing a guarantee to a client that a request has not been processed: The GOAWAY frame indicates the highest stream number that might have been processed. Requests on streams with higher numbers are therefore guaranteed to be safe to retry. The REFUSED_STREAM error code can be included in a RST_STREAM frame to indicate that the stream is being closed prior to any processing having occurred. Any request that was sent on the reset stream can be safely retried. Requests that have not been processed have not failed; clients MAY automatically retry them, even those with non-idempotent methods. A server MUST NOT indicate that a stream has not been processed unless it can guarantee that fact. If frames that are on a stream are passed to the application layer for any stream, then REFUSED_STREAM MUST NOT be used for that stream, and a GOAWAY frame MUST include a stream identifier that is greater than or equal to the given stream identifier. In addition to these mechanisms, the PING frame provides a way for a client to easily test a connection. Connections that remain idle can become broken as some middleboxes (for instance, network address translators, or load balancers) silently discard connection bindings. The PING frame allows a client to safely test whether a connection is still active without sending a request.
    HTTP/2 allows a server to pre-emptively send (or "push") responses (along with corresponding "promised" requests) to a client in association with a previous client-initiated request. This can be useful when the server knows the client will need to have those responses available in order to fully process the response to the original request. Pushing additional message exchanges in this fashion is optional, and is negotiated between individual endpoints. The SETTINGS_ENABLE_PUSH setting can be set to 0 to indicate that server push is disabled. Promised requests MUST be cacheable (see ), MUST be safe (see ) and MUST NOT include a request body. Clients that receive a promised request that is not cacheable, unsafe or that includes a request body MUST reset the stream with a stream error of type PROTOCOL_ERROR. Pushed responses that are cacheable (see ) can be stored by the client, if it implements a HTTP cache. Pushed responses are considered successfully validated on the origin server (e.g., if the "no-cache" cache response directive is present) while the stream identified by the promised stream ID is still open. Pushed responses that are not cacheable MUST NOT be stored by any HTTP cache. They MAY be made available to the application separately. An intermediary can receive pushes from the server and choose not to forward them on to the client. In other words, how to make use of the pushed information is up to that intermediary. Equally, the intermediary might choose to make additional pushes to the client, without any action taken by the server. A client cannot push. Thus, servers MUST treat the receipt of a PUSH_PROMISE frame as a connection error of type PROTOCOL_ERROR. Clients MUST reject any attempt to change the SETTINGS_ENABLE_PUSH setting to a value other than 0 by treating the message as a connection error of type PROTOCOL_ERROR.
    Server push is semantically equivalent to a server responding to a request; however, in this case that request is also sent by the server, as a PUSH_PROMISE frame. The PUSH_PROMISE frame includes a header block that contains a complete set of request header fields that the server attributes to the request. It is not possible to push a response to a request that includes a request body. Pushed responses are always associated with an explicit request from the client. The PUSH_PROMISE frames sent by the server are sent on that explicit request's stream. The PUSH_PROMISE frame also includes a promised stream identifier, chosen from the stream identifiers available to the server (see ). The header fields in PUSH_PROMISE and any subsequent CONTINUATION frames MUST be a valid and complete set of request header fields. The server MUST include a method in the :method header field that is safe and cacheable. If a client receives a PUSH_PROMISE that does not include a complete and valid set of header fields, or the :method header field identifies a method that is not safe, it MUST respond with a stream error of type PROTOCOL_ERROR. The server SHOULD send PUSH_PROMISE () frames prior to sending any frames that reference the promised responses. This avoids a race where clients issue requests prior to receiving any PUSH_PROMISE frames. For example, if the server receives a request for a document containing embedded links to multiple image files, and the server chooses to push those additional images to the client, sending push promises before the DATA frames that contain the image links ensures that the client is able to see the promises before discovering embedded links. Similarly, if the server pushes responses referenced by the header block (for instance, in Link header fields), sending the push promises before sending the header block ensures that clients do not request them. PUSH_PROMISE frames MUST NOT be sent by the client. PUSH_PROMISE frames can be sent by the server in response to any client-initiated stream, but the stream MUST be in either the "open" or "half closed (remote)" state with respect to the server. PUSH_PROMISE frames are interspersed with the frames that comprise a response, though they cannot be interspersed with HEADERS and CONTINUATION frames that comprise a single header block. Sending a PUSH_PROMISE frame creates a new stream and puts the stream into the “reserved (local)†state for the server and the “reserved (remote)†state for the client.
    After sending the PUSH_PROMISE frame, the server can begin delivering the pushed response as a response on a server-initiated stream that uses the promised stream identifier. The server uses this stream to transmit an HTTP response, using the same sequence of frames as defined in . This stream becomes "half closed" to the client after the initial HEADERS frame is sent. Once a client receives a PUSH_PROMISE frame and chooses to accept the pushed response, the client SHOULD NOT issue any requests for the promised response until after the promised stream has closed. If the client determines, for any reason, that it does not wish to receive the pushed response from the server, or if the server takes too long to begin sending the promised response, the client can send an RST_STREAM frame, using either the CANCEL or REFUSED_STREAM codes, and referencing the pushed stream's identifier. A client can use the SETTINGS_MAX_CONCURRENT_STREAMS setting to limit the number of responses that can be concurrently pushed by a server. Advertising a SETTINGS_MAX_CONCURRENT_STREAMS value of zero disables server push by preventing the server from creating the necessary streams. This does not prohibit a server from sending PUSH_PROMISE frames; clients need to reset any promised streams that are not wanted. Clients receiving a pushed response MUST validate that either the server is authoritative (see ), or the proxy that provided the pushed response is configured for the corresponding request. For example, a server that offers a certificate for only the example.com DNS-ID or Common Name is not permitted to push a response for https://www.example.org/doc. The response for a PUSH_PROMISE stream begins with a HEADERS frame, which immediately puts the stream into the “half closed (remote)†state for the server and “half closed (local)†state for the client, and ends with a frame bearing END_STREAM, which places the stream in the "closed" state. The client never sends a frame with the END_STREAM flag for a server push.
    In HTTP/1.x, the pseudo-method CONNECT () is used to convert an HTTP connection into a tunnel to a remote host. CONNECT is primarily used with HTTP proxies to establish a TLS session with an origin server for the purposes of interacting with https resources. In HTTP/2, the CONNECT method is used to establish a tunnel over a single HTTP/2 stream to a remote host, for similar purposes. The HTTP header field mapping works as defined in Request Header Fields, with a few differences. Specifically: The :method header field is set to CONNECT. The :scheme and :path header fields MUST be omitted. The :authority header field contains the host and port to connect to (equivalent to the authority-form of the request-target of CONNECT requests, see ). A proxy that supports CONNECT establishes a TCP connection to the server identified in the :authority header field. Once this connection is successfully established, the proxy sends a HEADERS frame containing a 2xx series status code to the client, as defined in . After the initial HEADERS frame sent by each peer, all subsequent DATA frames correspond to data sent on the TCP connection. The payload of any DATA frames sent by the client is transmitted by the proxy to the TCP server; data received from the TCP server is assembled into DATA frames by the proxy. Frame types other than DATA or stream management frames (RST_STREAM, WINDOW_UPDATE, and PRIORITY) MUST NOT be sent on a connected stream, and MUST be treated as a stream error if received. The TCP connection can be closed by either peer. The END_STREAM flag on a DATA frame is treated as being equivalent to the TCP FIN bit. A client is expected to send a DATA frame with the END_STREAM flag set after receiving a frame bearing the END_STREAM flag. A proxy that receives a DATA frame with the END_STREAM flag set sends the attached data with the FIN bit set on the last TCP segment. A proxy that receives a TCP segment with the FIN bit set sends a DATA frame with the END_STREAM flag set. Note that the final TCP segment or DATA frame could be empty. A TCP connection error is signaled with RST_STREAM. A proxy treats any error in the TCP connection, which includes receiving a TCP segment with the RST bit set, as a stream error of type CONNECT_ERROR. Correspondingly, a proxy MUST send a TCP segment with the RST bit set if it detects an error with the stream or the HTTP/2 connection.
    This section outlines attributes of the HTTP protocol that improve interoperability, reduce exposure to known security vulnerabilities, or reduce the potential for implementation variation.
    HTTP/2 connections are persistent. For best performance, it is expected clients will not close connections until it is determined that no further communication with a server is necessary (for example, when a user navigates away from a particular web page), or until the server closes the connection. Clients SHOULD NOT open more than one HTTP/2 connection to a given host and port pair, where host is derived from a URI, a selected alternative service, or a configured proxy. A client can create additional connections as replacements, either to replace connections that are near to exhausting the available stream identifier space, to refresh the keying material for a TLS connection, or to replace connections that have encountered errors. A client MAY open multiple connections to the same IP address and TCP port using different Server Name Indication values or to provide different TLS client certificates, but SHOULD avoid creating multiple connections with the same configuration. Servers are encouraged to maintain open connections for as long as possible, but are permitted to terminate idle connections if necessary. When either endpoint chooses to close the transport-layer TCP connection, the terminating endpoint SHOULD first send a GOAWAY () frame so that both endpoints can reliably determine whether previously sent frames have been processed and gracefully complete or terminate any necessary remaining tasks.
    Connections that are made to an origin servers, either directly or through a tunnel created using the CONNECT method MAY be reused for requests with multiple different URI authority components. A connection can be reused as long as the origin server is authoritative. For http resources, this depends on the host having resolved to the same IP address. For https resources, connection reuse additionally depends on having a certificate that is valid for the host in the URI. An origin server might offer a certificate with multiple subjectAltName attributes, or names with wildcards, one of which is valid for the authority in the URI. For example, a certificate with a subjectAltName of *.example.com might permit the use of the same connection for requests to URIs starting with https://a.example.com/ and https://b.example.com/. In some deployments, reusing a connection for multiple origins can result in requests being directed to the wrong origin server. For example, TLS termination might be performed by a middlebox that uses the TLS Server Name Indication (SNI) extension to select an origin server. This means that it is possible for clients to send confidential information to servers that might not be the intended target for the request, even though the server is otherwise authoritative. A server that does not wish clients to reuse connections can indicate that it is not authoritative for a request by sending a 421 (Misdirected Request) status code in response to the request (see ). A client that is configured to use a proxy over HTTP/2 directs requests to that proxy through a single connection. That is, all requests sent via a proxy reuse the connection to the proxy.
    The 421 (Misdirected Request) status code indicates that the request was directed at a server that is not able to produce a response. This can be sent by a server that is not configured to produce responses for the combination of scheme and authority that are included in the request URI. Clients receiving a 421 (Misdirected Request) response from a server MAY retry the request - whether the request method is idempotent or not - over a different connection. This is possible if a connection is reused () or if an alternative service is selected (). This status code MUST NOT be generated by proxies. A 421 response is cacheable by default; i.e., unless otherwise indicated by the method definition or explicit cache controls (see ).
    Implementations of HTTP/2 MUST support TLS 1.2 for HTTP/2 over TLS. The general TLS usage guidance in SHOULD be followed, with some additional restrictions that are specific to HTTP/2. An implementation of HTTP/2 over TLS MUST use TLS 1.2 or higher with the restrictions on feature set and cipher suite described in this section. Due to implementation limitations, it might not be possible to fail TLS negotiation. An endpoint MUST immediately terminate an HTTP/2 connection that does not meet these minimum requirements with a connection error of type INADEQUATE_SECURITY.
    The TLS implementation MUST support the Server Name Indication (SNI) extension to TLS. HTTP/2 clients MUST indicate the target domain name when negotiating TLS. The TLS implementation MUST disable compression. TLS compression can lead to the exposure of information that would not otherwise be revealed . Generic compression is unnecessary since HTTP/2 provides compression features that are more aware of context and therefore likely to be more appropriate for use for performance, security or other reasons. The TLS implementation MUST disable renegotiation. An endpoint MUST treat a TLS renegotiation as a connection error of type PROTOCOL_ERROR. Note that disabling renegotiation can result in long-lived connections becoming unusable due to limits on the number of messages the underlying cipher suite can encipher. A client MAY use renegotiation to provide confidentiality protection for client credentials offered in the handshake, but any renegotiation MUST occur prior to sending the connection preface. A server SHOULD request a client certificate if it sees a renegotiation request immediately after establishing a connection. This effectively prevents the use of renegotiation in response to a request for a specific protected resource. A future specification might provide a way to support this use case.
    The set of TLS cipher suites that are permitted in HTTP/2 is restricted. HTTP/2 MUST only be used with cipher suites that have ephemeral key exchange, such as the ephemeral Diffie-Hellman (DHE) or the elliptic curve variant (ECDHE). Ephemeral key exchange MUST have a minimum size of 2048 bits for DHE or security level of 128 bits for ECDHE. Clients MUST accept DHE sizes of up to 4096 bits. HTTP MUST NOT be used with cipher suites that use stream or block ciphers. Authenticated Encryption with Additional Data (AEAD) modes, such as the Galois Counter Model (GCM) mode for AES are acceptable. The effect of these restrictions is that TLS 1.2 implementations could have non-intersecting sets of available cipher suites, since these prevent the use of the cipher suite that TLS 1.2 makes mandatory. To avoid this problem, implementations of HTTP/2 that use TLS 1.2 MUST support TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 with P256 . Clients MAY advertise support of cipher suites that are prohibited by the above restrictions in order to allow for connection to servers that do not support HTTP/2. This enables a fallback to protocols without these constraints without the additional latency imposed by using a separate connection for fallback.
    HTTP/2 relies on the HTTP/1.1 definition of authority for determining whether a server is authoritative in providing a given response, see . This relies on local name resolution for the "http" URI scheme, and the authenticated server identity for the "https" scheme (see ).
    In a cross-protocol attack, an attacker causes a client to initiate a transaction in one protocol toward a server that understands a different protocol. An attacker might be able to cause the transaction to appear as valid transaction in the second protocol. In combination with the capabilities of the web context, this can be used to interact with poorly protected servers in private networks. Completing a TLS handshake with an ALPN identifier for HTTP/2 can be considered sufficient protection against cross protocol attacks. ALPN provides a positive indication that a server is willing to proceed with HTTP/2, which prevents attacks on other TLS-based protocols. The encryption in TLS makes it difficult for attackers to control the data which could be used in a cross-protocol attack on a cleartext protocol. The cleartext version of HTTP/2 has minimal protection against cross-protocol attacks. The connection preface contains a string that is designed to confuse HTTP/1.1 servers, but no special protection is offered for other protocols. A server that is willing to ignore parts of an HTTP/1.1 request containing an Upgrade header field in addition to the client connection preface could be exposed to a cross-protocol attack.
    HTTP/2 header field names and values are encoded as sequences of octets with a length prefix. This enables HTTP/2 to carry any string of octets as the name or value of a header field. An intermediary that translates HTTP/2 requests or responses into HTTP/1.1 directly could permit the creation of corrupted HTTP/1.1 messages. An attacker might exploit this behavior to cause the intermediary to create HTTP/1.1 messages with illegal header fields, extra header fields, or even new messages that are entirely falsified. Header field names or values that contain characters not permitted by HTTP/1.1, including carriage return (ASCII 0xd) or line feed (ASCII 0xa) MUST NOT be translated verbatim by an intermediary, as stipulated in . Translation from HTTP/1.x to HTTP/2 does not produce the same opportunity to an attacker. Intermediaries that perform translation to HTTP/2 MUST remove any instances of the obs-fold production from header field values.
    Pushed responses do not have an explicit request from the client; the request is provided by the server in the PUSH_PROMISE frame. Caching responses that are pushed is possible based on the guidance provided by the origin server in the Cache-Control header field. However, this can cause issues if a single server hosts more than one tenant. For example, a server might offer multiple users each a small portion of its URI space. Where multiple tenants share space on the same server, that server MUST ensure that tenants are not able to push representations of resources that they do not have authority over. Failure to enforce this would allow a tenant to provide a representation that would be served out of cache, overriding the actual representation that the authoritative tenant provides. Pushed responses for which an origin server is not authoritative (see ) are never cached or used.
    An HTTP/2 connection can demand a greater commitment of resources to operate than a HTTP/1.1 connection. The use of header compression and flow control depend on a commitment of resources for storing a greater amount of state. Settings for these features ensure that memory commitments for these features are strictly bounded. The number of PUSH_PROMISE frames is not constrained in the same fashion. A client that accepts server push SHOULD limit the number of streams it allows to be in the "reserved (remote)" state. Excessive number of server push streams can be treated as a stream error of type ENHANCE_YOUR_CALM. Processing capacity cannot be guarded as effectively as state capacity. The SETTINGS frame can be abused to cause a peer to expend additional processing time. This might be done by pointlessly changing SETTINGS parameters, setting multiple undefined parameters, or changing the same setting multiple times in the same frame. WINDOW_UPDATE or PRIORITY frames can be abused to cause an unnecessary waste of resources. Large numbers of small or empty frames can be abused to cause a peer to expend time processing frame headers. Note however that some uses are entirely legitimate, such as the sending of an empty DATA frame to end a stream. Header compression also offers some opportunities to waste processing resources; see for more details on potential abuses. Limits in SETTINGS parameters cannot be reduced instantaneously, which leaves an endpoint exposed to behavior from a peer that could exceed the new limits. In particular, immediately after establishing a connection, limits set by a server are not known to clients and could be exceeded without being an obvious protocol violation. All these features - i.e., SETTINGS changes, small frames, header compression - have legitimate uses. These features become a burden only when they are used unnecessarily or to excess. An endpoint that doesn't monitor this behavior exposes itself to a risk of denial of service attack. Implementations SHOULD track the use of these features and set limits on their use. An endpoint MAY treat activity that is suspicious as a connection error of type ENHANCE_YOUR_CALM.
    A large header block can cause an implementation to commit a large amount of state. Header fields that are critical for routing can appear toward the end of a header block, which prevents streaming of header fields to their ultimate destination. For this an other reasons, such as ensuring cache correctness, means that an endpoint might need to buffer the entire header block. Since there is no hard limit to the size of a header block, some endpoints could be forced commit a large amount of available memory for header fields. An endpoint can use the SETTINGS_MAX_HEADER_LIST_SIZE to advise peers of limits that might apply on the size of header blocks. This setting is only advisory, so endpoints MAY choose to send header blocks that exceed this limit and risk having the request or response being treated as malformed. This setting specific to a connection, so any request or response could encounter a hop with a lower, unknown limit. An intermediary can attempt to avoid this problem by passing on values presented by different peers, but they are not obligated to do so. A server that receives a larger header block than it is willing to handle can send an HTTP 431 (Request Header Fields Too Large) status code . A client can discard responses that it cannot process. The header block MUST be processed to ensure a consistent connection state, unless the connection is closed.
    HTTP/2 enables greater use of compression for both header fields () and entity bodies. Compression can allow an attacker to recover secret data when it is compressed in the same context as data under attacker control. There are demonstrable attacks on compression that exploit the characteristics of the web (e.g., ). The attacker induces multiple requests containing varying plaintext, observing the length of the resulting ciphertext in each, which reveals a shorter length when a guess about the secret is correct. Implementations communicating on a secure channel MUST NOT compress content that includes both confidential and attacker-controlled data unless separate compression dictionaries are used for each source of data. Compression MUST NOT be used if the source of data cannot be reliably determined. Generic stream compression, such as that provided by TLS MUST NOT be used with HTTP/2 (). Further considerations regarding the compression of header fields are described in .
    Padding within HTTP/2 is not intended as a replacement for general purpose padding, such as might be provided by TLS. Redundant padding could even be counterproductive. Correct application can depend on having specific knowledge of the data that is being padded. To mitigate attacks that rely on compression, disabling or limiting compression might be preferable to padding as a countermeasure. Padding can be used to obscure the exact size of frame content, and is provided to mitigate specific attacks within HTTP. For example, attacks where compressed content includes both attacker-controlled plaintext and secret data (see for example, ). Use of padding can result in less protection than might seem immediately obvious. At best, padding only makes it more difficult for an attacker to infer length information by increasing the number of frames an attacker has to observe. Incorrectly implemented padding schemes can be easily defeated. In particular, randomized padding with a predictable distribution provides very little protection; similarly, padding payloads to a fixed size exposes information as payload sizes cross the fixed size boundary, which could be possible if an attacker can control plaintext. Intermediaries SHOULD retain padding for DATA frames, but MAY drop padding for HEADERS and PUSH_PROMISE frames. A valid reason for an intermediary to change the amount of padding of frames is to improve the protections that padding provides.
    Several characteristics of HTTP/2 provide an observer an opportunity to correlate actions of a single client or server over time. This includes the value of settings, the manner in which flow control windows are managed, the way priorities are allocated to streams, timing of reactions to stimulus, and handling of any optional features. As far as this creates observable differences in behavior, they could be used as a basis for fingerprinting a specific client, as defined in .
    A string for identifying HTTP/2 is entered into the "Application Layer Protocol Negotiation (ALPN) Protocol IDs" registry established in . This document establishes a registry for frame types, settings, and error codes. These new registries are entered into a new "Hypertext Transfer Protocol (HTTP) 2 Parameters" section. This document registers the HTTP2-Settings header field for use in HTTP; and the 421 (Misdirected Request) status code. This document registers the PRI method for use in HTTP, to avoid collisions with the connection preface.
    This document creates two registrations for the identification of HTTP/2 in the "Application Layer Protocol Negotiation (ALPN) Protocol IDs" registry established in . The "h2" string identifies HTTP/2 when used over TLS: HTTP/2 over TLS 0x68 0x32 ("h2") This document The "h2c" string identifies HTTP/2 when used over cleartext TCP: HTTP/2 over TCP 0x68 0x32 0x63 ("h2c") This document
    This document establishes a registry for HTTP/2 frame type codes. The "HTTP/2 Frame Type" registry manages an 8-bit space. The "HTTP/2 Frame Type" registry operates under either of the "IETF Review" or "IESG Approval" policies for values between 0x00 and 0xef, with values between 0xf0 and 0xff being reserved for experimental use. New entries in this registry require the following information: A name or label for the frame type. The 8-bit code assigned to the frame type. A reference to a specification that includes a description of the frame layout, it's semantics and flags that the frame type uses, including any parts of the frame that are conditionally present based on the value of flags. The entries in the following table are registered by this document. Frame Type Code Section DATA0x0 HEADERS0x1 PRIORITY0x2 RST_STREAM0x3 SETTINGS0x4 PUSH_PROMISE0x5 PING0x6 GOAWAY0x7 WINDOW_UPDATE0x8 CONTINUATION0x9
    This document establishes a registry for HTTP/2 settings. The "HTTP/2 Settings" registry manages a 16-bit space. The "HTTP/2 Settings" registry operates under the "Expert Review" policy for values in the range from 0x0000 to 0xefff, with values between and 0xf000 and 0xffff being reserved for experimental use. New registrations are advised to provide the following information: A symbolic name for the setting. Specifying a setting name is optional. The 16-bit code assigned to the setting. An initial value for the setting. An optional reference to a specification that describes the use of the setting. An initial set of setting registrations can be found in . Name Code Initial Value Specification HEADER_TABLE_SIZE 0x14096 ENABLE_PUSH 0x21 MAX_CONCURRENT_STREAMS 0x3(infinite) INITIAL_WINDOW_SIZE 0x465535 MAX_FRAME_SIZE 0x516384 MAX_HEADER_LIST_SIZE 0x6(infinite)
    This document establishes a registry for HTTP/2 error codes. The "HTTP/2 Error Code" registry manages a 32-bit space. The "HTTP/2 Error Code" registry operates under the "Expert Review" policy. Registrations for error codes are required to include a description of the error code. An expert reviewer is advised to examine new registrations for possible duplication with existing error codes. Use of existing registrations is to be encouraged, but not mandated. New registrations are advised to provide the following information: A name for the error code. Specifying an error code name is optional. The 32-bit error code value. A brief description of the error code semantics, longer if no detailed specification is provided. An optional reference for a specification that defines the error code. The entries in the following table are registered by this document. Name Code Description Specification NO_ERROR0x0 Graceful shutdown PROTOCOL_ERROR0x1 Protocol error detected INTERNAL_ERROR0x2 Implementation fault FLOW_CONTROL_ERROR0x3 Flow control limits exceeded SETTINGS_TIMEOUT0x4 Settings not acknowledged STREAM_CLOSED0x5 Frame received for closed stream FRAME_SIZE_ERROR0x6 Frame size incorrect REFUSED_STREAM0x7 Stream not processed CANCEL0x8 Stream cancelled COMPRESSION_ERROR0x9 Compression state not updated CONNECT_ERROR0xa TCP connection error for CONNECT method ENHANCE_YOUR_CALM0xb Processing capacity exceeded INADEQUATE_SECURITY0xc Negotiated TLS parameters not acceptable
    This section registers the HTTP2-Settings header field in the Permanent Message Header Field Registry. HTTP2-Settings http standard IETF of this document This header field is only used by an HTTP/2 client for Upgrade-based negotiation.
    This section registers the PRI method in the HTTP Method Registry (). PRI No No of this document This method is never used by an actual client. This method will appear to be used when an HTTP/1.1 server or intermediary attempts to parse an HTTP/2 connection preface.
    This document registers the 421 (Misdirected Request) HTTP Status code in the Hypertext Transfer Protocol (HTTP) Status Code Registry (). 421 Misdirected Request of this document
    This document includes substantial input from the following individuals: Adam Langley, Wan-Teh Chang, Jim Morrison, Mark Nottingham, Alyssa Wilk, Costin Manolache, William Chan, Vitaliy Lvin, Joe Chan, Adam Barth, Ryan Hamilton, Gavin Peters, Kent Alstad, Kevin Lindsay, Paul Amer, Fan Yang, Jonathan Leighton (SPDY contributors). Gabriel Montenegro and Willy Tarreau (Upgrade mechanism). William Chan, Salvatore Loreto, Osama Mazahir, Gabriel Montenegro, Jitu Padhye, Roberto Peon, Rob Trace (Flow control). Mike Bishop (Extensibility). Mark Nottingham, Julian Reschke, James Snell, Jeff Pinner, Mike Bishop, Herve Ruellan (Substantial editorial contributions). Kari Hurtta, Tatsuhiro Tsujikawa, Greg Wilkins, Poul-Henning Kamp. Alexey Melnikov was an editor of this document during 2013. A substantial proportion of Martin's contribution was supported by Microsoft during his employment there.
    HPACK - Header Compression for HTTP/2 Transmission Control Protocol University of Southern California (USC)/Information Sciences Institute Key words for use in RFCs to Indicate Requirement Levels Harvard University
    sob@harvard.edu
    HTTP Over TLS Uniform Resource Identifier (URI): Generic Syntax The Base16, Base32, and Base64 Data Encodings Guidelines for Writing an IANA Considerations Section in RFCs Augmented BNF for Syntax Specifications: ABNF The Transport Layer Security (TLS) Protocol Version 1.2 Transport Layer Security (TLS) Extensions: Extension Definitions Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension TLS Elliptic Curve Cipher Suites with SHA-256/384 and AES Galois Counter Mode (GCM) Digital Signature Standard (DSS) NIST Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing Adobe Systems Incorporated
    fielding@gbiv.com
    greenbytes GmbH
    julian.reschke@greenbytes.de
    Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content Adobe Systems Incorporated
    fielding@gbiv.com
    greenbytes GmbH
    julian.reschke@greenbytes.de
    Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests Adobe Systems Incorporated
    fielding@gbiv.com
    greenbytes GmbH
    julian.reschke@greenbytes.de
    Hypertext Transfer Protocol (HTTP/1.1): Range Requests Adobe Systems Incorporated
    fielding@gbiv.com
    World Wide Web Consortium
    ylafon@w3.org
    greenbytes GmbH
    julian.reschke@greenbytes.de
    Hypertext Transfer Protocol (HTTP/1.1): Caching Adobe Systems Incorporated
    fielding@gbiv.com
    Akamai
    mnot@mnot.net
    greenbytes GmbH
    julian.reschke@greenbytes.de
    Hypertext Transfer Protocol (HTTP/1.1): Authentication Adobe Systems Incorporated
    fielding@gbiv.com
    greenbytes GmbH
    julian.reschke@greenbytes.de
    HTTP State Management Mechanism
    TCP Extensions for High Performance Transport Layer Security Protocol Compression Methods Additional HTTP Status Codes Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS) AES Galois Counter Mode (GCM) Cipher Suites for TLS HTML5 Latest version available at . Talking to Yourself for Fun and Profit BREACH: Reviving the CRIME Attack Registration Procedures for Message Header Fields Nine by Nine
    GK-IETF@ninebynine.org
    BEA Systems
    mnot@pobox.com
    HP Labs
    JeffMogul@acm.org
    Recommendations for Secure Use of TLS and DTLS HTTP Alternative Services Akamai Mozilla greenbytes
    This section is to be removed by RFC Editor before publication.
    Renamed Not Authoritative status code to Misdirected Request.
    Pseudo-header fields are now required to appear strictly before regular ones. Restored 1xx series status codes, except 101. Changed frame length field 24-bits. Expanded frame header to 9 octets. Added a setting to limit the damage. Added a setting to advise peers of header set size limits. Removed segments. Made non-semantic-bearing HEADERS frames illegal in the HTTP mapping.
    Restored extensibility options. Restricting TLS cipher suites to AEAD only. Removing Content-Encoding requirements. Permitting the use of PRIORITY after stream close. Removed ALTSVC frame. Removed BLOCKED frame. Reducing the maximum padding size to 256 octets; removing padding from CONTINUATION frames. Removed per-frame GZIP compression.
    Added BLOCKED frame (at risk). Simplified priority scheme. Added DATA per-frame GZIP compression.
    Changed "connection header" to "connection preface" to avoid confusion. Added dependency-based stream prioritization. Added "h2c" identifier to distinguish between cleartext and secured HTTP/2. Adding missing padding to PUSH_PROMISE. Integrate ALTSVC frame and supporting text. Dropping requirement on "deflate" Content-Encoding. Improving security considerations around use of compression.
    Adding padding for data frames. Renumbering frame types, error codes, and settings. Adding INADEQUATE_SECURITY error code. Updating TLS usage requirements to 1.2; forbidding TLS compression. Removing extensibility for frames and settings. Changing setting identifier size. Removing the ability to disable flow control. Changing the protocol identification token to "h2". Changing the use of :authority to make it optional and to allow userinfo in non-HTTP cases. Allowing split on 0x0 for Cookie. Reserved PRI method in HTTP/1.1 to avoid possible future collisions.
    Added cookie crumbling for more efficient header compression. Added header field ordering with the value-concatenation mechanism.
    Marked draft for implementation.
    Adding definition for CONNECT method. Constraining the use of push to safe, cacheable methods with no request body. Changing from :host to :authority to remove any potential confusion. Adding setting for header compression table size. Adding settings acknowledgement. Removing unnecessary and potentially problematic flags from CONTINUATION. Added denial of service considerations.
    Marking the draft ready for implementation. Renumbering END_PUSH_PROMISE flag. Editorial clarifications and changes.
    Added CONTINUATION frame for HEADERS and PUSH_PROMISE. PUSH_PROMISE is no longer implicitly prohibited if SETTINGS_MAX_CONCURRENT_STREAMS is zero. Push expanded to allow all safe methods without a request body. Clarified the use of HTTP header fields in requests and responses. Prohibited HTTP/1.1 hop-by-hop header fields. Requiring that intermediaries not forward requests with missing or illegal routing :-headers. Clarified requirements around handling different frames after stream close, stream reset and GOAWAY. Added more specific prohibitions for sending of different frame types in various stream states. Making the last received setting value the effective value. Clarified requirements on TLS version, extension and ciphers.
    Committed major restructuring atrocities. Added reference to first header compression draft. Added more formal description of frame lifecycle. Moved END_STREAM (renamed from FINAL) back to HEADERS/DATA. Removed HEADERS+PRIORITY, added optional priority to HEADERS frame. Added PRIORITY frame.
    Added continuations to frames carrying header blocks. Replaced use of "session" with "connection" to avoid confusion with other HTTP stateful concepts, like cookies. Removed "message". Switched to TLS ALPN from NPN. Editorial changes.
    Added IANA considerations section for frame types, error codes and settings. Removed data frame compression. Added PUSH_PROMISE. Added globally applicable flags to framing. Removed zlib-based header compression mechanism. Updated references. Clarified stream identifier reuse. Removed CREDENTIALS frame and associated mechanisms. Added advice against naive implementation of flow control. Added session header section. Restructured frame header. Removed distinction between data and control frames. Altered flow control properties to include session-level limits. Added note on cacheability of pushed resources and multiple tenant servers. Changed protocol label form based on discussions.
    Changed title throughout. Removed section on Incompatibilities with SPDY draft#2. Changed INTERNAL_ERROR on GOAWAY to have a value of 2 . Replaced abstract and introduction. Added section on starting HTTP/2.0, including upgrade mechanism. Removed unused references. Added flow control principles based on .
    Adopted as base for draft-ietf-httpbis-http2. Updated authors/editors list. Added status note.
    golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/transport.go000066400000000000000000001244041264464372400240710ustar00rootroot00000000000000// Copyright 2015 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. // Transport code. package http2 import ( "bufio" "bytes" "compress/gzip" "crypto/tls" "errors" "fmt" "io" "io/ioutil" "log" "net" "net/http" "sort" "strconv" "strings" "sync" "golang.org/x/net/http2/hpack" ) const ( // transportDefaultConnFlow is how many connection-level flow control // tokens we give the server at start-up, past the default 64k. transportDefaultConnFlow = 1 << 30 // transportDefaultStreamFlow is how many stream-level flow // control tokens we announce to the peer, and how many bytes // we buffer per stream. transportDefaultStreamFlow = 4 << 20 // transportDefaultStreamMinRefresh is the minimum number of bytes we'll send // a stream-level WINDOW_UPDATE for at a time. transportDefaultStreamMinRefresh = 4 << 10 defaultUserAgent = "Go-http-client/2.0" ) // Transport is an HTTP/2 Transport. // // A Transport internally caches connections to servers. It is safe // for concurrent use by multiple goroutines. type Transport struct { // DialTLS specifies an optional dial function for creating // TLS connections for requests. // // If DialTLS is nil, tls.Dial is used. // // If the returned net.Conn has a ConnectionState method like tls.Conn, // it will be used to set http.Response.TLS. DialTLS func(network, addr string, cfg *tls.Config) (net.Conn, error) // TLSClientConfig specifies the TLS configuration to use with // tls.Client. If nil, the default configuration is used. TLSClientConfig *tls.Config // ConnPool optionally specifies an alternate connection pool to use. // If nil, the default is used. ConnPool ClientConnPool // DisableCompression, if true, prevents the Transport from // requesting compression with an "Accept-Encoding: gzip" // request header when the Request contains no existing // Accept-Encoding value. If the Transport requests gzip on // its own and gets a gzipped response, it's transparently // decoded in the Response.Body. However, if the user // explicitly requested gzip it is not automatically // uncompressed. DisableCompression bool // MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to // send in the initial settings frame. It is how many bytes // of response headers are allow. Unlike the http2 spec, zero here // means to use a default limit (currently 10MB). If you actually // want to advertise an ulimited value to the peer, Transport // interprets the highest possible value here (0xffffffff or 1<<32-1) // to mean no limit. MaxHeaderListSize uint32 connPoolOnce sync.Once connPoolOrDef ClientConnPool // non-nil version of ConnPool } func (t *Transport) maxHeaderListSize() uint32 { if t.MaxHeaderListSize == 0 { return 10 << 20 } if t.MaxHeaderListSize == 0xffffffff { return 0 } return t.MaxHeaderListSize } func (t *Transport) disableCompression() bool { if t.DisableCompression { return true } // TODO: also disable if this transport is somehow linked to an http1 Transport // and it's configured there? return false } var errTransportVersion = errors.New("http2: ConfigureTransport is only supported starting at Go 1.6") // ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2. // It requires Go 1.6 or later and returns an error if the net/http package is too old // or if t1 has already been HTTP/2-enabled. func ConfigureTransport(t1 *http.Transport) error { return configureTransport(t1) // in configure_transport.go (go1.6) or go15.go } func (t *Transport) connPool() ClientConnPool { t.connPoolOnce.Do(t.initConnPool) return t.connPoolOrDef } func (t *Transport) initConnPool() { if t.ConnPool != nil { t.connPoolOrDef = t.ConnPool } else { t.connPoolOrDef = &clientConnPool{t: t} } } // ClientConn is the state of a single HTTP/2 client connection to an // HTTP/2 server. type ClientConn struct { t *Transport tconn net.Conn // usually *tls.Conn, except specialized impls tlsState *tls.ConnectionState // nil only for specialized impls // readLoop goroutine fields: readerDone chan struct{} // closed on error readerErr error // set before readerDone is closed mu sync.Mutex // guards following cond *sync.Cond // hold mu; broadcast on flow/closed changes flow flow // our conn-level flow control quota (cs.flow is per stream) inflow flow // peer's conn-level flow control closed bool goAway *GoAwayFrame // if non-nil, the GoAwayFrame we received streams map[uint32]*clientStream // client-initiated nextStreamID uint32 bw *bufio.Writer br *bufio.Reader fr *Framer // Settings from peer: maxFrameSize uint32 maxConcurrentStreams uint32 initialWindowSize uint32 hbuf bytes.Buffer // HPACK encoder writes into this henc *hpack.Encoder freeBuf [][]byte wmu sync.Mutex // held while writing; acquire AFTER wmu if holding both werr error // first write error that has occurred } // clientStream is the state for a single HTTP/2 stream. One of these // is created for each Transport.RoundTrip call. type clientStream struct { cc *ClientConn req *http.Request ID uint32 resc chan resAndError bufPipe pipe // buffered pipe with the flow-controlled response payload requestedGzip bool flow flow // guarded by cc.mu inflow flow // guarded by cc.mu bytesRemain int64 // -1 means unknown; owned by transportResponseBody.Read readErr error // sticky read error; owned by transportResponseBody.Read stopReqBody bool // stop writing req body; guarded by cc.mu peerReset chan struct{} // closed on peer reset resetErr error // populated before peerReset is closed done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu // owned by clientConnReadLoop: pastHeaders bool // got HEADERS w/ END_HEADERS pastTrailers bool // got second HEADERS frame w/ END_HEADERS trailer http.Header // accumulated trailers resTrailer *http.Header // client's Response.Trailer } // awaitRequestCancel runs in its own goroutine and waits for the user // to either cancel a RoundTrip request (using the provided // Request.Cancel channel), or for the request to be done (any way it // might be removed from the cc.streams map: peer reset, successful // completion, TCP connection breakage, etc) func (cs *clientStream) awaitRequestCancel(cancel <-chan struct{}) { if cancel == nil { return } select { case <-cancel: cs.bufPipe.CloseWithError(errRequestCanceled) cs.cc.writeStreamReset(cs.ID, ErrCodeCancel, nil) case <-cs.done: } } // checkReset reports any error sent in a RST_STREAM frame by the // server. func (cs *clientStream) checkReset() error { select { case <-cs.peerReset: return cs.resetErr default: return nil } } func (cs *clientStream) abortRequestBodyWrite() { cc := cs.cc cc.mu.Lock() cs.stopReqBody = true cc.cond.Broadcast() cc.mu.Unlock() } type stickyErrWriter struct { w io.Writer err *error } func (sew stickyErrWriter) Write(p []byte) (n int, err error) { if *sew.err != nil { return 0, *sew.err } n, err = sew.w.Write(p) *sew.err = err return } var ErrNoCachedConn = errors.New("http2: no cached connection was available") // RoundTripOpt are options for the Transport.RoundTripOpt method. type RoundTripOpt struct { // OnlyCachedConn controls whether RoundTripOpt may // create a new TCP connection. If set true and // no cached connection is available, RoundTripOpt // will return ErrNoCachedConn. OnlyCachedConn bool } func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { return t.RoundTripOpt(req, RoundTripOpt{}) } // authorityAddr returns a given authority (a host/IP, or host:port / ip:port) // and returns a host:port. The port 443 is added if needed. func authorityAddr(authority string) (addr string) { if _, _, err := net.SplitHostPort(authority); err == nil { return authority } return net.JoinHostPort(authority, "443") } // RoundTripOpt is like RoundTrip, but takes options. func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error) { if req.URL.Scheme != "https" { return nil, errors.New("http2: unsupported scheme") } addr := authorityAddr(req.URL.Host) for { cc, err := t.connPool().GetClientConn(req, addr) if err != nil { t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err) return nil, err } res, err := cc.RoundTrip(req) if shouldRetryRequest(req, err) { continue } if err != nil { t.vlogf("RoundTrip failure: %v", err) return nil, err } return res, nil } } // CloseIdleConnections closes any connections which were previously // connected from previous requests but are now sitting idle. // It does not interrupt any connections currently in use. func (t *Transport) CloseIdleConnections() { if cp, ok := t.connPool().(*clientConnPool); ok { cp.closeIdleConnections() } } var ( errClientConnClosed = errors.New("http2: client conn is closed") errClientConnUnusable = errors.New("http2: client conn not usable") ) func shouldRetryRequest(req *http.Request, err error) bool { // TODO: retry GET requests (no bodies) more aggressively, if shutdown // before response. return err == errClientConnUnusable } func (t *Transport) dialClientConn(addr string) (*ClientConn, error) { host, _, err := net.SplitHostPort(addr) if err != nil { return nil, err } tconn, err := t.dialTLS()("tcp", addr, t.newTLSConfig(host)) if err != nil { return nil, err } return t.NewClientConn(tconn) } func (t *Transport) newTLSConfig(host string) *tls.Config { cfg := new(tls.Config) if t.TLSClientConfig != nil { *cfg = *t.TLSClientConfig } cfg.NextProtos = []string{NextProtoTLS} // TODO: don't override if already in list cfg.ServerName = host return cfg } func (t *Transport) dialTLS() func(string, string, *tls.Config) (net.Conn, error) { if t.DialTLS != nil { return t.DialTLS } return t.dialTLSDefault } func (t *Transport) dialTLSDefault(network, addr string, cfg *tls.Config) (net.Conn, error) { cn, err := tls.Dial(network, addr, cfg) if err != nil { return nil, err } if err := cn.Handshake(); err != nil { return nil, err } if !cfg.InsecureSkipVerify { if err := cn.VerifyHostname(cfg.ServerName); err != nil { return nil, err } } state := cn.ConnectionState() if p := state.NegotiatedProtocol; p != NextProtoTLS { return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, NextProtoTLS) } if !state.NegotiatedProtocolIsMutual { return nil, errors.New("http2: could not negotiate protocol mutually") } return cn, nil } func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) { if VerboseLogs { t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr()) } if _, err := c.Write(clientPreface); err != nil { t.vlogf("client preface write error: %v", err) return nil, err } cc := &ClientConn{ t: t, tconn: c, readerDone: make(chan struct{}), nextStreamID: 1, maxFrameSize: 16 << 10, // spec default initialWindowSize: 65535, // spec default maxConcurrentStreams: 1000, // "infinite", per spec. 1000 seems good enough. streams: make(map[uint32]*clientStream), } cc.cond = sync.NewCond(&cc.mu) cc.flow.add(int32(initialWindowSize)) // TODO: adjust this writer size to account for frame size + // MTU + crypto/tls record padding. cc.bw = bufio.NewWriter(stickyErrWriter{c, &cc.werr}) cc.br = bufio.NewReader(c) cc.fr = NewFramer(cc.bw, cc.br) // TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on // henc in response to SETTINGS frames? cc.henc = hpack.NewEncoder(&cc.hbuf) type connectionStater interface { ConnectionState() tls.ConnectionState } if cs, ok := c.(connectionStater); ok { state := cs.ConnectionState() cc.tlsState = &state } initialSettings := []Setting{ Setting{ID: SettingEnablePush, Val: 0}, Setting{ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow}, } if max := t.maxHeaderListSize(); max != 0 { initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max}) } cc.fr.WriteSettings(initialSettings...) cc.fr.WriteWindowUpdate(0, transportDefaultConnFlow) cc.inflow.add(transportDefaultConnFlow + initialWindowSize) cc.bw.Flush() if cc.werr != nil { return nil, cc.werr } // Read the obligatory SETTINGS frame f, err := cc.fr.ReadFrame() if err != nil { return nil, err } sf, ok := f.(*SettingsFrame) if !ok { return nil, fmt.Errorf("expected settings frame, got: %T", f) } cc.fr.WriteSettingsAck() cc.bw.Flush() sf.ForeachSetting(func(s Setting) error { switch s.ID { case SettingMaxFrameSize: cc.maxFrameSize = s.Val case SettingMaxConcurrentStreams: cc.maxConcurrentStreams = s.Val case SettingInitialWindowSize: cc.initialWindowSize = s.Val default: // TODO(bradfitz): handle more; at least SETTINGS_HEADER_TABLE_SIZE? t.vlogf("Unhandled Setting: %v", s) } return nil }) go cc.readLoop() return cc, nil } func (cc *ClientConn) setGoAway(f *GoAwayFrame) { cc.mu.Lock() defer cc.mu.Unlock() cc.goAway = f } func (cc *ClientConn) CanTakeNewRequest() bool { cc.mu.Lock() defer cc.mu.Unlock() return cc.canTakeNewRequestLocked() } func (cc *ClientConn) canTakeNewRequestLocked() bool { return cc.goAway == nil && int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) && cc.nextStreamID < 2147483647 } func (cc *ClientConn) closeIfIdle() { cc.mu.Lock() if len(cc.streams) > 0 { cc.mu.Unlock() return } cc.closed = true // TODO: do clients send GOAWAY too? maybe? Just Close: cc.mu.Unlock() cc.tconn.Close() } const maxAllocFrameSize = 512 << 10 // frameBuffer returns a scratch buffer suitable for writing DATA frames. // They're capped at the min of the peer's max frame size or 512KB // (kinda arbitrarily), but definitely capped so we don't allocate 4GB // bufers. func (cc *ClientConn) frameScratchBuffer() []byte { cc.mu.Lock() size := cc.maxFrameSize if size > maxAllocFrameSize { size = maxAllocFrameSize } for i, buf := range cc.freeBuf { if len(buf) >= int(size) { cc.freeBuf[i] = nil cc.mu.Unlock() return buf[:size] } } cc.mu.Unlock() return make([]byte, size) } func (cc *ClientConn) putFrameScratchBuffer(buf []byte) { cc.mu.Lock() defer cc.mu.Unlock() const maxBufs = 4 // arbitrary; 4 concurrent requests per conn? investigate. if len(cc.freeBuf) < maxBufs { cc.freeBuf = append(cc.freeBuf, buf) return } for i, old := range cc.freeBuf { if old == nil { cc.freeBuf[i] = buf return } } // forget about it. } // errRequestCanceled is a copy of net/http's errRequestCanceled because it's not // exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests. var errRequestCanceled = errors.New("net/http: request canceled") func commaSeparatedTrailers(req *http.Request) (string, error) { keys := make([]string, 0, len(req.Trailer)) for k := range req.Trailer { k = http.CanonicalHeaderKey(k) switch k { case "Transfer-Encoding", "Trailer", "Content-Length": return "", &badStringError{"invalid Trailer key", k} } keys = append(keys, k) } if len(keys) > 0 { sort.Strings(keys) // TODO: could do better allocation-wise here, but trailers are rare, // so being lazy for now. return strings.Join(keys, ","), nil } return "", nil } func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) { trailers, err := commaSeparatedTrailers(req) if err != nil { return nil, err } hasTrailers := trailers != "" cc.mu.Lock() if cc.closed || !cc.canTakeNewRequestLocked() { cc.mu.Unlock() return nil, errClientConnUnusable } cs := cc.newStream() cs.req = req hasBody := req.Body != nil // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? if !cc.t.disableCompression() && req.Header.Get("Accept-Encoding") == "" && req.Header.Get("Range") == "" && req.Method != "HEAD" { // Request gzip only, not deflate. Deflate is ambiguous and // not as universally supported anyway. // See: http://www.gzip.org/zlib/zlib_faq.html#faq38 // // Note that we don't request this for HEAD requests, // due to a bug in nginx: // http://trac.nginx.org/nginx/ticket/358 // https://golang.org/issue/5522 // // We don't request gzip if the request is for a range, since // auto-decoding a portion of a gzipped document will just fail // anyway. See https://golang.org/issue/8923 cs.requestedGzip = true } // we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is // sent by writeRequestBody below, along with any Trailers, // again in form HEADERS{1}, CONTINUATION{0,}) hdrs := cc.encodeHeaders(req, cs.requestedGzip, trailers) cc.wmu.Lock() endStream := !hasBody && !hasTrailers werr := cc.writeHeaders(cs.ID, endStream, hdrs) cc.wmu.Unlock() cc.mu.Unlock() if werr != nil { if hasBody { req.Body.Close() // per RoundTripper contract } cc.forgetStreamID(cs.ID) // Don't bother sending a RST_STREAM (our write already failed; // no need to keep writing) return nil, werr } var bodyCopyErrc chan error // result of body copy if hasBody { bodyCopyErrc = make(chan error, 1) go func() { bodyCopyErrc <- cs.writeRequestBody(req.Body) }() } readLoopResCh := cs.resc requestCanceledCh := requestCancel(req) requestCanceled := false for { select { case re := <-readLoopResCh: res := re.res if re.err != nil || res.StatusCode > 299 { // On error or status code 3xx, 4xx, 5xx, etc abort any // ongoing write, assuming that the server doesn't care // about our request body. If the server replied with 1xx or // 2xx, however, then assume the server DOES potentially // want our body (e.g. full-duplex streaming: // golang.org/issue/13444). If it turns out the server // doesn't, they'll RST_STREAM us soon enough. This is a // heuristic to avoid adding knobs to Transport. Hopefully // we can keep it. cs.abortRequestBodyWrite() } if re.err != nil { cc.forgetStreamID(cs.ID) return nil, re.err } res.Request = req res.TLS = cc.tlsState return res, nil case <-requestCanceledCh: cc.forgetStreamID(cs.ID) cs.abortRequestBodyWrite() if !hasBody { cc.writeStreamReset(cs.ID, ErrCodeCancel, nil) return nil, errRequestCanceled } // If we have a body, wait for the body write to be // finished before sending the RST_STREAM frame. requestCanceled = true requestCanceledCh = nil // to prevent spins readLoopResCh = nil // ignore responses at this point case <-cs.peerReset: if requestCanceled { // They hung up on us first. No need to write a RST_STREAM. // But prioritize the request canceled error value, since // it's likely related. (same spirit as http1 code) return nil, errRequestCanceled } // processResetStream already removed the // stream from the streams map; no need for // forgetStreamID. return nil, cs.resetErr case err := <-bodyCopyErrc: if requestCanceled { cc.writeStreamReset(cs.ID, ErrCodeCancel, nil) return nil, errRequestCanceled } if err != nil { return nil, err } } } } // requires cc.wmu be held func (cc *ClientConn) writeHeaders(streamID uint32, endStream bool, hdrs []byte) error { first := true // first frame written (HEADERS is first, then CONTINUATION) frameSize := int(cc.maxFrameSize) for len(hdrs) > 0 && cc.werr == nil { chunk := hdrs if len(chunk) > frameSize { chunk = chunk[:frameSize] } hdrs = hdrs[len(chunk):] endHeaders := len(hdrs) == 0 if first { cc.fr.WriteHeaders(HeadersFrameParam{ StreamID: streamID, BlockFragment: chunk, EndStream: endStream, EndHeaders: endHeaders, }) first = false } else { cc.fr.WriteContinuation(streamID, endHeaders, chunk) } } // TODO(bradfitz): this Flush could potentially block (as // could the WriteHeaders call(s) above), which means they // wouldn't respond to Request.Cancel being readable. That's // rare, but this should probably be in a goroutine. cc.bw.Flush() return cc.werr } // errAbortReqBodyWrite is an internal error value. // It doesn't escape to callers. var errAbortReqBodyWrite = errors.New("http2: aborting request body write") func (cs *clientStream) writeRequestBody(body io.ReadCloser) (err error) { cc := cs.cc sentEnd := false // whether we sent the final DATA frame w/ END_STREAM buf := cc.frameScratchBuffer() defer cc.putFrameScratchBuffer(buf) defer func() { // TODO: write h12Compare test showing whether // Request.Body is closed by the Transport, // and in multiple cases: server replies <=299 and >299 // while still writing request body cerr := body.Close() if err == nil { err = cerr } }() req := cs.req hasTrailers := req.Trailer != nil var sawEOF bool for !sawEOF { n, err := body.Read(buf) if err == io.EOF { sawEOF = true err = nil } else if err != nil { return err } remain := buf[:n] for len(remain) > 0 && err == nil { var allowed int32 allowed, err = cs.awaitFlowControl(len(remain)) if err != nil { return err } cc.wmu.Lock() data := remain[:allowed] remain = remain[allowed:] sentEnd = sawEOF && len(remain) == 0 && !hasTrailers err = cc.fr.WriteData(cs.ID, sentEnd, data) if err == nil { // TODO(bradfitz): this flush is for latency, not bandwidth. // Most requests won't need this. Make this opt-in or opt-out? // Use some heuristic on the body type? Nagel-like timers? // Based on 'n'? Only last chunk of this for loop, unless flow control // tokens are low? For now, always: err = cc.bw.Flush() } cc.wmu.Unlock() } if err != nil { return err } } cc.wmu.Lock() if !sentEnd { var trls []byte if hasTrailers { cc.mu.Lock() trls = cc.encodeTrailers(req) cc.mu.Unlock() } // Avoid forgetting to send an END_STREAM if the encoded // trailers are 0 bytes. Both results produce and END_STREAM. if len(trls) > 0 { err = cc.writeHeaders(cs.ID, true, trls) } else { err = cc.fr.WriteData(cs.ID, true, nil) } } if ferr := cc.bw.Flush(); ferr != nil && err == nil { err = ferr } cc.wmu.Unlock() return err } // awaitFlowControl waits for [1, min(maxBytes, cc.cs.maxFrameSize)] flow // control tokens from the server. // It returns either the non-zero number of tokens taken or an error // if the stream is dead. func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) { cc := cs.cc cc.mu.Lock() defer cc.mu.Unlock() for { if cc.closed { return 0, errClientConnClosed } if cs.stopReqBody { return 0, errAbortReqBodyWrite } if err := cs.checkReset(); err != nil { return 0, err } if a := cs.flow.available(); a > 0 { take := a if int(take) > maxBytes { take = int32(maxBytes) // can't truncate int; take is int32 } if take > int32(cc.maxFrameSize) { take = int32(cc.maxFrameSize) } cs.flow.take(take) return take, nil } cc.cond.Wait() } } type badStringError struct { what string str string } func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) } // requires cc.mu be held. func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trailers string) []byte { cc.hbuf.Reset() host := req.Host if host == "" { host = req.URL.Host } // 8.1.2.3 Request Pseudo-Header Fields // The :path pseudo-header field includes the path and query parts of the // target URI (the path-absolute production and optionally a '?' character // followed by the query production (see Sections 3.3 and 3.4 of // [RFC3986]). cc.writeHeader(":authority", host) cc.writeHeader(":method", req.Method) if req.Method != "CONNECT" { cc.writeHeader(":path", req.URL.RequestURI()) cc.writeHeader(":scheme", "https") } if trailers != "" { cc.writeHeader("trailer", trailers) } var didUA bool for k, vv := range req.Header { lowKey := strings.ToLower(k) if lowKey == "host" { continue } if lowKey == "user-agent" { // Match Go's http1 behavior: at most one // User-Agent. If set to nil or empty string, // then omit it. Otherwise if not mentioned, // include the default (below). didUA = true if len(vv) < 1 { continue } vv = vv[:1] if vv[0] == "" { continue } } for _, v := range vv { cc.writeHeader(lowKey, v) } } if addGzipHeader { cc.writeHeader("accept-encoding", "gzip") } if !didUA { cc.writeHeader("user-agent", defaultUserAgent) } return cc.hbuf.Bytes() } // requires cc.mu be held. func (cc *ClientConn) encodeTrailers(req *http.Request) []byte { cc.hbuf.Reset() for k, vv := range req.Trailer { // Transfer-Encoding, etc.. have already been filter at the // start of RoundTrip lowKey := strings.ToLower(k) for _, v := range vv { cc.writeHeader(lowKey, v) } } return cc.hbuf.Bytes() } func (cc *ClientConn) writeHeader(name, value string) { if VerboseLogs { log.Printf("http2: Transport encoding header %q = %q", name, value) } cc.henc.WriteField(hpack.HeaderField{Name: name, Value: value}) } type resAndError struct { res *http.Response err error } // requires cc.mu be held. func (cc *ClientConn) newStream() *clientStream { cs := &clientStream{ cc: cc, ID: cc.nextStreamID, resc: make(chan resAndError, 1), peerReset: make(chan struct{}), done: make(chan struct{}), } cs.flow.add(int32(cc.initialWindowSize)) cs.flow.setConnFlow(&cc.flow) cs.inflow.add(transportDefaultStreamFlow) cs.inflow.setConnFlow(&cc.inflow) cc.nextStreamID += 2 cc.streams[cs.ID] = cs return cs } func (cc *ClientConn) forgetStreamID(id uint32) { cc.streamByID(id, true) } func (cc *ClientConn) streamByID(id uint32, andRemove bool) *clientStream { cc.mu.Lock() defer cc.mu.Unlock() cs := cc.streams[id] if andRemove && cs != nil { delete(cc.streams, id) close(cs.done) } return cs } // clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop. type clientConnReadLoop struct { cc *ClientConn activeRes map[uint32]*clientStream // keyed by streamID hdec *hpack.Decoder // Fields reset on each HEADERS: nextRes *http.Response sawRegHeader bool // saw non-pseudo header reqMalformed error // non-nil once known to be malformed lastHeaderEndsStream bool headerListSize int64 // actually uint32, but easier math this way } // readLoop runs in its own goroutine and reads and dispatches frames. func (cc *ClientConn) readLoop() { rl := &clientConnReadLoop{ cc: cc, activeRes: make(map[uint32]*clientStream), } rl.hdec = hpack.NewDecoder(initialHeaderTableSize, rl.onNewHeaderField) defer rl.cleanup() cc.readerErr = rl.run() if ce, ok := cc.readerErr.(ConnectionError); ok { cc.wmu.Lock() cc.fr.WriteGoAway(0, ErrCode(ce), nil) cc.wmu.Unlock() } } func (rl *clientConnReadLoop) cleanup() { cc := rl.cc defer cc.tconn.Close() defer cc.t.connPool().MarkDead(cc) defer close(cc.readerDone) // Close any response bodies if the server closes prematurely. // TODO: also do this if we've written the headers but not // gotten a response yet. err := cc.readerErr if err == io.EOF { err = io.ErrUnexpectedEOF } cc.mu.Lock() for _, cs := range rl.activeRes { cs.bufPipe.CloseWithError(err) } for _, cs := range cc.streams { select { case cs.resc <- resAndError{err: err}: default: } close(cs.done) } cc.closed = true cc.cond.Broadcast() cc.mu.Unlock() } func (rl *clientConnReadLoop) run() error { cc := rl.cc for { f, err := cc.fr.ReadFrame() if err != nil { cc.vlogf("Transport readFrame error: (%T) %v", err, err) } if se, ok := err.(StreamError); ok { // TODO: deal with stream errors from the framer. return se } else if err != nil { return err } if VerboseLogs { cc.vlogf("http2: Transport received %s", summarizeFrame(f)) } switch f := f.(type) { case *HeadersFrame: err = rl.processHeaders(f) case *ContinuationFrame: err = rl.processContinuation(f) case *DataFrame: err = rl.processData(f) case *GoAwayFrame: err = rl.processGoAway(f) case *RSTStreamFrame: err = rl.processResetStream(f) case *SettingsFrame: err = rl.processSettings(f) case *PushPromiseFrame: err = rl.processPushPromise(f) case *WindowUpdateFrame: err = rl.processWindowUpdate(f) case *PingFrame: err = rl.processPing(f) default: cc.logf("Transport: unhandled response frame type %T", f) } if err != nil { return err } } } func (rl *clientConnReadLoop) processHeaders(f *HeadersFrame) error { rl.sawRegHeader = false rl.reqMalformed = nil rl.lastHeaderEndsStream = f.StreamEnded() rl.headerListSize = 0 rl.nextRes = &http.Response{ Proto: "HTTP/2.0", ProtoMajor: 2, Header: make(http.Header), } rl.hdec.SetEmitEnabled(true) return rl.processHeaderBlockFragment(f.HeaderBlockFragment(), f.StreamID, f.HeadersEnded()) } func (rl *clientConnReadLoop) processContinuation(f *ContinuationFrame) error { return rl.processHeaderBlockFragment(f.HeaderBlockFragment(), f.StreamID, f.HeadersEnded()) } func (rl *clientConnReadLoop) processHeaderBlockFragment(frag []byte, streamID uint32, finalFrag bool) error { cc := rl.cc streamEnded := rl.lastHeaderEndsStream cs := cc.streamByID(streamID, streamEnded && finalFrag) if cs == nil { // We'd get here if we canceled a request while the // server was mid-way through replying with its // headers. (The case of a CONTINUATION arriving // without HEADERS would be rejected earlier by the // Framer). So if this was just something we canceled, // ignore it. return nil } if cs.pastHeaders { rl.hdec.SetEmitFunc(func(f hpack.HeaderField) { rl.onNewTrailerField(cs, f) }) } else { rl.hdec.SetEmitFunc(rl.onNewHeaderField) } _, err := rl.hdec.Write(frag) if err != nil { return ConnectionError(ErrCodeCompression) } if finalFrag { if err := rl.hdec.Close(); err != nil { return ConnectionError(ErrCodeCompression) } } if !finalFrag { return nil } if !cs.pastHeaders { cs.pastHeaders = true } else { // We're dealing with trailers. (and specifically the // final frame of headers) if cs.pastTrailers { // Too many HEADERS frames for this stream. return ConnectionError(ErrCodeProtocol) } cs.pastTrailers = true if !streamEnded { // We expect that any header block fragment // frame for trailers with END_HEADERS also // has END_STREAM. return ConnectionError(ErrCodeProtocol) } rl.endStream(cs) return nil } if rl.reqMalformed != nil { cs.resc <- resAndError{err: rl.reqMalformed} rl.cc.writeStreamReset(cs.ID, ErrCodeProtocol, rl.reqMalformed) return nil } res := rl.nextRes if res.StatusCode == 100 { // Just skip 100-continue response headers for now. // TODO: golang.org/issue/13851 for doing it properly. cs.pastHeaders = false // do it all again return nil } if !streamEnded || cs.req.Method == "HEAD" { res.ContentLength = -1 if clens := res.Header["Content-Length"]; len(clens) == 1 { if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil { res.ContentLength = clen64 } else { // TODO: care? unlike http/1, it won't mess up our framing, so it's // more safe smuggling-wise to ignore. } } else if len(clens) > 1 { // TODO: care? unlike http/1, it won't mess up our framing, so it's // more safe smuggling-wise to ignore. } } if streamEnded { res.Body = noBody } else { buf := new(bytes.Buffer) // TODO(bradfitz): recycle this garbage cs.bufPipe = pipe{b: buf} cs.bytesRemain = res.ContentLength res.Body = transportResponseBody{cs} go cs.awaitRequestCancel(requestCancel(cs.req)) if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" { res.Header.Del("Content-Encoding") res.Header.Del("Content-Length") res.ContentLength = -1 res.Body = &gzipReader{body: res.Body} } } cs.resTrailer = &res.Trailer rl.activeRes[cs.ID] = cs cs.resc <- resAndError{res: res} rl.nextRes = nil // unused now; will be reset next HEADERS frame return nil } // transportResponseBody is the concrete type of Transport.RoundTrip's // Response.Body. It is an io.ReadCloser. On Read, it reads from cs.body. // On Close it sends RST_STREAM if EOF wasn't already seen. type transportResponseBody struct { cs *clientStream } func (b transportResponseBody) Read(p []byte) (n int, err error) { cs := b.cs cc := cs.cc if cs.readErr != nil { return 0, cs.readErr } n, err = b.cs.bufPipe.Read(p) if cs.bytesRemain != -1 { if int64(n) > cs.bytesRemain { n = int(cs.bytesRemain) if err == nil { err = errors.New("net/http: server replied with more than declared Content-Length; truncated") cc.writeStreamReset(cs.ID, ErrCodeProtocol, err) } cs.readErr = err return int(cs.bytesRemain), err } cs.bytesRemain -= int64(n) if err == io.EOF && cs.bytesRemain > 0 { err = io.ErrUnexpectedEOF cs.readErr = err return n, err } } if n == 0 { // No flow control tokens to send back. return } cc.mu.Lock() defer cc.mu.Unlock() var connAdd, streamAdd int32 // Check the conn-level first, before the stream-level. if v := cc.inflow.available(); v < transportDefaultConnFlow/2 { connAdd = transportDefaultConnFlow - v cc.inflow.add(connAdd) } if err == nil { // No need to refresh if the stream is over or failed. if v := cs.inflow.available(); v < transportDefaultStreamFlow-transportDefaultStreamMinRefresh { streamAdd = transportDefaultStreamFlow - v cs.inflow.add(streamAdd) } } if connAdd != 0 || streamAdd != 0 { cc.wmu.Lock() defer cc.wmu.Unlock() if connAdd != 0 { cc.fr.WriteWindowUpdate(0, mustUint31(connAdd)) } if streamAdd != 0 { cc.fr.WriteWindowUpdate(cs.ID, mustUint31(streamAdd)) } cc.bw.Flush() } return } var errClosedResponseBody = errors.New("http2: response body closed") func (b transportResponseBody) Close() error { cs := b.cs if cs.bufPipe.Err() != io.EOF { // TODO: write test for this cs.cc.writeStreamReset(cs.ID, ErrCodeCancel, nil) } cs.bufPipe.BreakWithError(errClosedResponseBody) return nil } func (rl *clientConnReadLoop) processData(f *DataFrame) error { cc := rl.cc cs := cc.streamByID(f.StreamID, f.StreamEnded()) if cs == nil { return nil } data := f.Data() // Check connection-level flow control. cc.mu.Lock() if cs.inflow.available() >= int32(len(data)) { cs.inflow.take(int32(len(data))) } else { cc.mu.Unlock() return ConnectionError(ErrCodeFlowControl) } cc.mu.Unlock() if _, err := cs.bufPipe.Write(data); err != nil { return err } if f.StreamEnded() { rl.endStream(cs) } return nil } var errInvalidTrailers = errors.New("http2: invalid trailers") func (rl *clientConnReadLoop) endStream(cs *clientStream) { // TODO: check that any declared content-length matches, like // server.go's (*stream).endStream method. err := io.EOF code := cs.copyTrailers if rl.reqMalformed != nil { err = rl.reqMalformed code = nil } cs.bufPipe.closeWithErrorAndCode(err, code) delete(rl.activeRes, cs.ID) } func (cs *clientStream) copyTrailers() { for k, vv := range cs.trailer { t := cs.resTrailer if *t == nil { *t = make(http.Header) } (*t)[k] = vv } } func (rl *clientConnReadLoop) processGoAway(f *GoAwayFrame) error { cc := rl.cc cc.t.connPool().MarkDead(cc) if f.ErrCode != 0 { // TODO: deal with GOAWAY more. particularly the error code cc.vlogf("transport got GOAWAY with error code = %v", f.ErrCode) } cc.setGoAway(f) return nil } func (rl *clientConnReadLoop) processSettings(f *SettingsFrame) error { cc := rl.cc cc.mu.Lock() defer cc.mu.Unlock() return f.ForeachSetting(func(s Setting) error { switch s.ID { case SettingMaxFrameSize: cc.maxFrameSize = s.Val case SettingMaxConcurrentStreams: cc.maxConcurrentStreams = s.Val case SettingInitialWindowSize: // TODO: error if this is too large. // TODO: adjust flow control of still-open // frames by the difference of the old initial // window size and this one. cc.initialWindowSize = s.Val default: // TODO(bradfitz): handle more settings? SETTINGS_HEADER_TABLE_SIZE probably. cc.vlogf("Unhandled Setting: %v", s) } return nil }) } func (rl *clientConnReadLoop) processWindowUpdate(f *WindowUpdateFrame) error { cc := rl.cc cs := cc.streamByID(f.StreamID, false) if f.StreamID != 0 && cs == nil { return nil } cc.mu.Lock() defer cc.mu.Unlock() fl := &cc.flow if cs != nil { fl = &cs.flow } if !fl.add(int32(f.Increment)) { return ConnectionError(ErrCodeFlowControl) } cc.cond.Broadcast() return nil } func (rl *clientConnReadLoop) processResetStream(f *RSTStreamFrame) error { cs := rl.cc.streamByID(f.StreamID, true) if cs == nil { // TODO: return error if server tries to RST_STEAM an idle stream return nil } select { case <-cs.peerReset: // Already reset. // This is the only goroutine // which closes this, so there // isn't a race. default: err := StreamError{cs.ID, f.ErrCode} cs.resetErr = err close(cs.peerReset) cs.bufPipe.CloseWithError(err) cs.cc.cond.Broadcast() // wake up checkReset via clientStream.awaitFlowControl } delete(rl.activeRes, cs.ID) return nil } func (rl *clientConnReadLoop) processPing(f *PingFrame) error { if f.IsAck() { // 6.7 PING: " An endpoint MUST NOT respond to PING frames // containing this flag." return nil } cc := rl.cc cc.wmu.Lock() defer cc.wmu.Unlock() if err := cc.fr.WritePing(true, f.Data); err != nil { return err } return cc.bw.Flush() } func (rl *clientConnReadLoop) processPushPromise(f *PushPromiseFrame) error { // We told the peer we don't want them. // Spec says: // "PUSH_PROMISE MUST NOT be sent if the SETTINGS_ENABLE_PUSH // setting of the peer endpoint is set to 0. An endpoint that // has set this setting and has received acknowledgement MUST // treat the receipt of a PUSH_PROMISE frame as a connection // error (Section 5.4.1) of type PROTOCOL_ERROR." return ConnectionError(ErrCodeProtocol) } func (cc *ClientConn) writeStreamReset(streamID uint32, code ErrCode, err error) { // TODO: do something with err? send it as a debug frame to the peer? // But that's only in GOAWAY. Invent a new frame type? Is there one already? cc.wmu.Lock() cc.fr.WriteRSTStream(streamID, code) cc.bw.Flush() cc.wmu.Unlock() } var ( errResponseHeaderListSize = errors.New("http2: response header list larger than advertised limit") errInvalidHeaderKey = errors.New("http2: invalid header key") errPseudoTrailers = errors.New("http2: invalid pseudo header in trailers") ) func (rl *clientConnReadLoop) checkHeaderField(f hpack.HeaderField) bool { if rl.reqMalformed != nil { return false } const headerFieldOverhead = 32 // per spec rl.headerListSize += int64(len(f.Name)) + int64(len(f.Value)) + headerFieldOverhead if max := rl.cc.t.maxHeaderListSize(); max != 0 && rl.headerListSize > int64(max) { rl.hdec.SetEmitEnabled(false) rl.reqMalformed = errResponseHeaderListSize return false } if !validHeader(f.Name) { rl.reqMalformed = errInvalidHeaderKey return false } isPseudo := strings.HasPrefix(f.Name, ":") if isPseudo { if rl.sawRegHeader { rl.reqMalformed = errors.New("http2: invalid pseudo header after regular header") return false } } else { rl.sawRegHeader = true } return true } // onNewHeaderField runs on the readLoop goroutine whenever a new // hpack header field is decoded. func (rl *clientConnReadLoop) onNewHeaderField(f hpack.HeaderField) { cc := rl.cc if VerboseLogs { cc.logf("http2: Transport decoded %v", f) } if !rl.checkHeaderField(f) { return } isPseudo := strings.HasPrefix(f.Name, ":") if isPseudo { switch f.Name { case ":status": code, err := strconv.Atoi(f.Value) if err != nil { rl.reqMalformed = errors.New("http2: invalid :status") return } rl.nextRes.Status = f.Value + " " + http.StatusText(code) rl.nextRes.StatusCode = code default: // "Endpoints MUST NOT generate pseudo-header // fields other than those defined in this // document." rl.reqMalformed = fmt.Errorf("http2: unknown response pseudo header %q", f.Name) } return } key := http.CanonicalHeaderKey(f.Name) if key == "Trailer" { t := rl.nextRes.Trailer if t == nil { t = make(http.Header) rl.nextRes.Trailer = t } foreachHeaderElement(f.Value, func(v string) { t[http.CanonicalHeaderKey(v)] = nil }) } else { rl.nextRes.Header.Add(key, f.Value) } } func (rl *clientConnReadLoop) onNewTrailerField(cs *clientStream, f hpack.HeaderField) { if VerboseLogs { rl.cc.logf("http2: Transport decoded trailer %v", f) } if !rl.checkHeaderField(f) { return } if strings.HasPrefix(f.Name, ":") { // Pseudo-header fields MUST NOT appear in // trailers. Endpoints MUST treat a request or // response that contains undefined or invalid // pseudo-header fields as malformed. rl.reqMalformed = errPseudoTrailers return } key := http.CanonicalHeaderKey(f.Name) // The spec says one must predeclare their trailers but in practice // popular users (which is to say the only user we found) do not so we // violate the spec and accept all of them. const acceptAllTrailers = true if _, ok := (*cs.resTrailer)[key]; ok || acceptAllTrailers { if cs.trailer == nil { cs.trailer = make(http.Header) } cs.trailer[key] = append(cs.trailer[key], f.Value) } } func (cc *ClientConn) logf(format string, args ...interface{}) { cc.t.logf(format, args...) } func (cc *ClientConn) vlogf(format string, args ...interface{}) { cc.t.vlogf(format, args...) } func (t *Transport) vlogf(format string, args ...interface{}) { if VerboseLogs { t.logf(format, args...) } } func (t *Transport) logf(format string, args ...interface{}) { log.Printf(format, args...) } var noBody io.ReadCloser = ioutil.NopCloser(bytes.NewReader(nil)) func strSliceContains(ss []string, s string) bool { for _, v := range ss { if v == s { return true } } return false } type erringRoundTripper struct{ err error } func (rt erringRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, rt.err } // gzipReader wraps a response body so it can lazily // call gzip.NewReader on the first call to Read type gzipReader struct { body io.ReadCloser // underlying Response.Body zr io.Reader // lazily-initialized gzip reader } func (gz *gzipReader) Read(p []byte) (n int, err error) { if gz.zr == nil { gz.zr, err = gzip.NewReader(gz.body) if err != nil { return 0, err } } return gz.zr.Read(p) } func (gz *gzipReader) Close() error { return gz.body.Close() } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/transport_test.go000066400000000000000000001010241264464372400251210ustar00rootroot00000000000000// Copyright 2015 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 http2 import ( "bufio" "bytes" "crypto/tls" "errors" "flag" "fmt" "io" "io/ioutil" "log" "math/rand" "net" "net/http" "net/url" "os" "reflect" "strconv" "strings" "sync" "sync/atomic" "testing" "time" "golang.org/x/net/http2/hpack" ) var ( extNet = flag.Bool("extnet", false, "do external network tests") transportHost = flag.String("transporthost", "http2.golang.org", "hostname to use for TestTransport") insecure = flag.Bool("insecure", false, "insecure TLS dials") // TODO: dead code. remove? ) var tlsConfigInsecure = &tls.Config{InsecureSkipVerify: true} func TestTransportExternal(t *testing.T) { if !*extNet { t.Skip("skipping external network test") } req, _ := http.NewRequest("GET", "https://"+*transportHost+"/", nil) rt := &Transport{TLSClientConfig: tlsConfigInsecure} res, err := rt.RoundTrip(req) if err != nil { t.Fatalf("%v", err) } res.Write(os.Stdout) } func TestTransport(t *testing.T) { const body = "sup" st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, body) }, optOnlyServer) defer st.Close() tr := &Transport{TLSClientConfig: tlsConfigInsecure} defer tr.CloseIdleConnections() req, err := http.NewRequest("GET", st.ts.URL, nil) if err != nil { t.Fatal(err) } res, err := tr.RoundTrip(req) if err != nil { t.Fatal(err) } defer res.Body.Close() t.Logf("Got res: %+v", res) if g, w := res.StatusCode, 200; g != w { t.Errorf("StatusCode = %v; want %v", g, w) } if g, w := res.Status, "200 OK"; g != w { t.Errorf("Status = %q; want %q", g, w) } wantHeader := http.Header{ "Content-Length": []string{"3"}, "Content-Type": []string{"text/plain; charset=utf-8"}, "Date": []string{"XXX"}, // see cleanDate } cleanDate(res) if !reflect.DeepEqual(res.Header, wantHeader) { t.Errorf("res Header = %v; want %v", res.Header, wantHeader) } if res.Request != req { t.Errorf("Response.Request = %p; want %p", res.Request, req) } if res.TLS == nil { t.Error("Response.TLS = nil; want non-nil") } slurp, err := ioutil.ReadAll(res.Body) if err != nil { t.Errorf("Body read: %v", err) } else if string(slurp) != body { t.Errorf("Body = %q; want %q", slurp, body) } } func TestTransportReusesConns(t *testing.T) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, r.RemoteAddr) }, optOnlyServer) defer st.Close() tr := &Transport{TLSClientConfig: tlsConfigInsecure} defer tr.CloseIdleConnections() get := func() string { req, err := http.NewRequest("GET", st.ts.URL, nil) if err != nil { t.Fatal(err) } res, err := tr.RoundTrip(req) if err != nil { t.Fatal(err) } defer res.Body.Close() slurp, err := ioutil.ReadAll(res.Body) if err != nil { t.Fatalf("Body read: %v", err) } addr := strings.TrimSpace(string(slurp)) if addr == "" { t.Fatalf("didn't get an addr in response") } return addr } first := get() second := get() if first != second { t.Errorf("first and second responses were on different connections: %q vs %q", first, second) } } // Tests that the Transport only keeps one pending dial open per destination address. // https://golang.org/issue/13397 func TestTransportGroupsPendingDials(t *testing.T) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, r.RemoteAddr) }, optOnlyServer) defer st.Close() tr := &Transport{ TLSClientConfig: tlsConfigInsecure, } defer tr.CloseIdleConnections() var ( mu sync.Mutex dials = map[string]int{} ) var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() req, err := http.NewRequest("GET", st.ts.URL, nil) if err != nil { t.Error(err) return } res, err := tr.RoundTrip(req) if err != nil { t.Error(err) return } defer res.Body.Close() slurp, err := ioutil.ReadAll(res.Body) if err != nil { t.Errorf("Body read: %v", err) } addr := strings.TrimSpace(string(slurp)) if addr == "" { t.Errorf("didn't get an addr in response") } mu.Lock() dials[addr]++ mu.Unlock() }() } wg.Wait() if len(dials) != 1 { t.Errorf("saw %d dials; want 1: %v", len(dials), dials) } tr.CloseIdleConnections() if err := retry(50, 10*time.Millisecond, func() error { cp, ok := tr.connPool().(*clientConnPool) if !ok { return fmt.Errorf("Conn pool is %T; want *clientConnPool", tr.connPool()) } cp.mu.Lock() defer cp.mu.Unlock() if len(cp.dialing) != 0 { return fmt.Errorf("dialing map = %v; want empty", cp.dialing) } if len(cp.conns) != 0 { return fmt.Errorf("conns = %v; want empty", cp.conns) } if len(cp.keys) != 0 { return fmt.Errorf("keys = %v; want empty", cp.keys) } return nil }); err != nil { t.Errorf("State of pool after CloseIdleConnections: %v", err) } } func retry(tries int, delay time.Duration, fn func() error) error { var err error for i := 0; i < tries; i++ { err = fn() if err == nil { return nil } time.Sleep(delay) } return err } func TestTransportAbortClosesPipes(t *testing.T) { shutdown := make(chan struct{}) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { w.(http.Flusher).Flush() <-shutdown }, optOnlyServer, ) defer st.Close() defer close(shutdown) // we must shutdown before st.Close() to avoid hanging done := make(chan struct{}) requestMade := make(chan struct{}) go func() { defer close(done) tr := &Transport{TLSClientConfig: tlsConfigInsecure} req, err := http.NewRequest("GET", st.ts.URL, nil) if err != nil { t.Fatal(err) } res, err := tr.RoundTrip(req) if err != nil { t.Fatal(err) } defer res.Body.Close() close(requestMade) _, err = ioutil.ReadAll(res.Body) if err == nil { t.Error("expected error from res.Body.Read") } }() <-requestMade // Now force the serve loop to end, via closing the connection. st.closeConn() // deadlock? that's a bug. select { case <-done: case <-time.After(3 * time.Second): t.Fatal("timeout") } } // TODO: merge this with TestTransportBody to make TestTransportRequest? This // could be a table-driven test with extra goodies. func TestTransportPath(t *testing.T) { gotc := make(chan *url.URL, 1) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { gotc <- r.URL }, optOnlyServer, ) defer st.Close() tr := &Transport{TLSClientConfig: tlsConfigInsecure} defer tr.CloseIdleConnections() const ( path = "/testpath" query = "q=1" ) surl := st.ts.URL + path + "?" + query req, err := http.NewRequest("POST", surl, nil) if err != nil { t.Fatal(err) } c := &http.Client{Transport: tr} res, err := c.Do(req) if err != nil { t.Fatal(err) } defer res.Body.Close() got := <-gotc if got.Path != path { t.Errorf("Read Path = %q; want %q", got.Path, path) } if got.RawQuery != query { t.Errorf("Read RawQuery = %q; want %q", got.RawQuery, query) } } func randString(n int) string { rnd := rand.New(rand.NewSource(int64(n))) b := make([]byte, n) for i := range b { b[i] = byte(rnd.Intn(256)) } return string(b) } var bodyTests = []struct { body string noContentLen bool }{ {body: "some message"}, {body: "some message", noContentLen: true}, {body: ""}, {body: "", noContentLen: true}, {body: strings.Repeat("a", 1<<20), noContentLen: true}, {body: strings.Repeat("a", 1<<20)}, {body: randString(16<<10 - 1)}, {body: randString(16 << 10)}, {body: randString(16<<10 + 1)}, {body: randString(512<<10 - 1)}, {body: randString(512 << 10)}, {body: randString(512<<10 + 1)}, {body: randString(1<<20 - 1)}, {body: randString(1 << 20)}, {body: randString(1<<20 + 2)}, } func TestTransportBody(t *testing.T) { gotc := make(chan interface{}, 1) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { slurp, err := ioutil.ReadAll(r.Body) if err != nil { gotc <- err } else { gotc <- string(slurp) } }, optOnlyServer, ) defer st.Close() for i, tt := range bodyTests { tr := &Transport{TLSClientConfig: tlsConfigInsecure} defer tr.CloseIdleConnections() var body io.Reader = strings.NewReader(tt.body) if tt.noContentLen { body = struct{ io.Reader }{body} // just a Reader, hiding concrete type and other methods } req, err := http.NewRequest("POST", st.ts.URL, body) if err != nil { t.Fatalf("#%d: %v", i, err) } c := &http.Client{Transport: tr} res, err := c.Do(req) if err != nil { t.Fatalf("#%d: %v", i, err) } defer res.Body.Close() got := <-gotc if err, ok := got.(error); ok { t.Fatalf("#%d: %v", i, err) } else if got.(string) != tt.body { got := got.(string) t.Errorf("#%d: Read body mismatch.\n got: %q (len %d)\nwant: %q (len %d)", i, shortString(got), len(got), shortString(tt.body), len(tt.body)) } } } func shortString(v string) string { const maxLen = 100 if len(v) <= maxLen { return v } return fmt.Sprintf("%v[...%d bytes omitted...]%v", v[:maxLen/2], len(v)-maxLen, v[len(v)-maxLen/2:]) } func TestTransportDialTLS(t *testing.T) { var mu sync.Mutex // guards following var gotReq, didDial bool ts := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { mu.Lock() gotReq = true mu.Unlock() }, optOnlyServer, ) defer ts.Close() tr := &Transport{ DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) { mu.Lock() didDial = true mu.Unlock() cfg.InsecureSkipVerify = true c, err := tls.Dial(netw, addr, cfg) if err != nil { return nil, err } return c, c.Handshake() }, } defer tr.CloseIdleConnections() client := &http.Client{Transport: tr} res, err := client.Get(ts.ts.URL) if err != nil { t.Fatal(err) } res.Body.Close() mu.Lock() if !gotReq { t.Error("didn't get request") } if !didDial { t.Error("didn't use dial hook") } } func TestConfigureTransport(t *testing.T) { t1 := &http.Transport{} err := ConfigureTransport(t1) if err == errTransportVersion { t.Skip(err) } if err != nil { t.Fatal(err) } if got := fmt.Sprintf("%#v", *t1); !strings.Contains(got, `"h2"`) { // Laziness, to avoid buildtags. t.Errorf("stringification of HTTP/1 transport didn't contain \"h2\": %v", got) } wantNextProtos := []string{"h2", "http/1.1"} if t1.TLSClientConfig == nil { t.Errorf("nil t1.TLSClientConfig") } else if !reflect.DeepEqual(t1.TLSClientConfig.NextProtos, wantNextProtos) { t.Errorf("TLSClientConfig.NextProtos = %q; want %q", t1.TLSClientConfig.NextProtos, wantNextProtos) } if err := ConfigureTransport(t1); err == nil { t.Error("unexpected success on second call to ConfigureTransport") } // And does it work? st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, r.Proto) }, optOnlyServer) defer st.Close() t1.TLSClientConfig.InsecureSkipVerify = true c := &http.Client{Transport: t1} res, err := c.Get(st.ts.URL) if err != nil { t.Fatal(err) } slurp, err := ioutil.ReadAll(res.Body) if err != nil { t.Fatal(err) } if got, want := string(slurp), "HTTP/2.0"; got != want { t.Errorf("body = %q; want %q", got, want) } } type capitalizeReader struct { r io.Reader } func (cr capitalizeReader) Read(p []byte) (n int, err error) { n, err = cr.r.Read(p) for i, b := range p[:n] { if b >= 'a' && b <= 'z' { p[i] = b - ('a' - 'A') } } return } type flushWriter struct { w io.Writer } func (fw flushWriter) Write(p []byte) (n int, err error) { n, err = fw.w.Write(p) if f, ok := fw.w.(http.Flusher); ok { f.Flush() } return } type clientTester struct { t *testing.T tr *Transport sc, cc net.Conn // server and client conn fr *Framer // server's framer client func() error server func() error } func newClientTester(t *testing.T) *clientTester { var dialOnce struct { sync.Mutex dialed bool } ct := &clientTester{ t: t, } ct.tr = &Transport{ TLSClientConfig: tlsConfigInsecure, DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { dialOnce.Lock() defer dialOnce.Unlock() if dialOnce.dialed { return nil, errors.New("only one dial allowed in test mode") } dialOnce.dialed = true return ct.cc, nil }, } ln := newLocalListener(t) cc, err := net.Dial("tcp", ln.Addr().String()) if err != nil { t.Fatal(err) } sc, err := ln.Accept() if err != nil { t.Fatal(err) } ln.Close() ct.cc = cc ct.sc = sc ct.fr = NewFramer(sc, sc) return ct } func newLocalListener(t *testing.T) net.Listener { ln, err := net.Listen("tcp4", "127.0.0.1:0") if err == nil { return ln } ln, err = net.Listen("tcp6", "[::1]:0") if err != nil { t.Fatal(err) } return ln } func (ct *clientTester) greet() { buf := make([]byte, len(ClientPreface)) _, err := io.ReadFull(ct.sc, buf) if err != nil { ct.t.Fatalf("reading client preface: %v", err) } f, err := ct.fr.ReadFrame() if err != nil { ct.t.Fatalf("Reading client settings frame: %v", err) } if sf, ok := f.(*SettingsFrame); !ok { ct.t.Fatalf("Wanted client settings frame; got %v", f) _ = sf // stash it away? } if err := ct.fr.WriteSettings(); err != nil { ct.t.Fatal(err) } if err := ct.fr.WriteSettingsAck(); err != nil { ct.t.Fatal(err) } } func (ct *clientTester) cleanup() { ct.tr.CloseIdleConnections() } func (ct *clientTester) run() { errc := make(chan error, 2) ct.start("client", errc, ct.client) ct.start("server", errc, ct.server) defer ct.cleanup() for i := 0; i < 2; i++ { if err := <-errc; err != nil { ct.t.Error(err) return } } } func (ct *clientTester) start(which string, errc chan<- error, fn func() error) { go func() { finished := false var err error defer func() { if !finished { err = fmt.Errorf("%s goroutine didn't finish.", which) } else if err != nil { err = fmt.Errorf("%s: %v", which, err) } errc <- err }() err = fn() finished = true }() } type countingReader struct { n *int64 } func (r countingReader) Read(p []byte) (n int, err error) { for i := range p { p[i] = byte(i) } atomic.AddInt64(r.n, int64(len(p))) return len(p), err } func TestTransportReqBodyAfterResponse_200(t *testing.T) { testTransportReqBodyAfterResponse(t, 200) } func TestTransportReqBodyAfterResponse_403(t *testing.T) { testTransportReqBodyAfterResponse(t, 403) } func testTransportReqBodyAfterResponse(t *testing.T, status int) { const bodySize = 10 << 20 ct := newClientTester(t) ct.client = func() error { var n int64 // atomic req, err := http.NewRequest("PUT", "https://dummy.tld/", io.LimitReader(countingReader{&n}, bodySize)) if err != nil { return err } res, err := ct.tr.RoundTrip(req) if err != nil { return fmt.Errorf("RoundTrip: %v", err) } defer res.Body.Close() if res.StatusCode != status { return fmt.Errorf("status code = %v; want %v", res.StatusCode, status) } slurp, err := ioutil.ReadAll(res.Body) if err != nil { return fmt.Errorf("Slurp: %v", err) } if len(slurp) > 0 { return fmt.Errorf("unexpected body: %q", slurp) } if status == 200 { if got := atomic.LoadInt64(&n); got != bodySize { return fmt.Errorf("For 200 response, Transport wrote %d bytes; want %d", got, bodySize) } } else { if got := atomic.LoadInt64(&n); got == 0 || got >= bodySize { return fmt.Errorf("For %d response, Transport wrote %d bytes; want (0,%d) exclusive", status, got, bodySize) } } return nil } ct.server = func() error { ct.greet() var buf bytes.Buffer enc := hpack.NewEncoder(&buf) var dataRecv int64 var closed bool for { f, err := ct.fr.ReadFrame() if err != nil { return err } //println(fmt.Sprintf("server got frame: %v", f)) switch f := f.(type) { case *WindowUpdateFrame, *SettingsFrame: case *HeadersFrame: if !f.HeadersEnded() { return fmt.Errorf("headers should have END_HEADERS be ended: %v", f) } if f.StreamEnded() { return fmt.Errorf("headers contains END_STREAM unexpectedly: %v", f) } time.Sleep(50 * time.Millisecond) // let client send body enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)}) ct.fr.WriteHeaders(HeadersFrameParam{ StreamID: f.StreamID, EndHeaders: true, EndStream: false, BlockFragment: buf.Bytes(), }) case *DataFrame: dataLen := len(f.Data()) dataRecv += int64(dataLen) if dataLen > 0 { if err := ct.fr.WriteWindowUpdate(0, uint32(dataLen)); err != nil { return err } if err := ct.fr.WriteWindowUpdate(f.StreamID, uint32(dataLen)); err != nil { return err } } if !closed && ((status != 200 && dataRecv > 0) || (status == 200 && dataRecv == bodySize)) { closed = true if err := ct.fr.WriteData(f.StreamID, true, nil); err != nil { return err } return nil } default: return fmt.Errorf("Unexpected client frame %v", f) } } return nil } ct.run() } // See golang.org/issue/13444 func TestTransportFullDuplex(t *testing.T) { st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) // redundant but for clarity w.(http.Flusher).Flush() io.Copy(flushWriter{w}, capitalizeReader{r.Body}) fmt.Fprintf(w, "bye.\n") }, optOnlyServer) defer st.Close() tr := &Transport{TLSClientConfig: tlsConfigInsecure} defer tr.CloseIdleConnections() c := &http.Client{Transport: tr} pr, pw := io.Pipe() req, err := http.NewRequest("PUT", st.ts.URL, ioutil.NopCloser(pr)) if err != nil { log.Fatal(err) } res, err := c.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() if res.StatusCode != 200 { t.Fatalf("StatusCode = %v; want %v", res.StatusCode, 200) } bs := bufio.NewScanner(res.Body) want := func(v string) { if !bs.Scan() { t.Fatalf("wanted to read %q but Scan() = false, err = %v", v, bs.Err()) } } write := func(v string) { _, err := io.WriteString(pw, v) if err != nil { t.Fatalf("pipe write: %v", err) } } write("foo\n") want("FOO") write("bar\n") want("BAR") pw.Close() want("bye.") if err := bs.Err(); err != nil { t.Fatal(err) } } func TestTransportConnectRequest(t *testing.T) { gotc := make(chan *http.Request, 1) st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) { gotc <- r }, optOnlyServer) defer st.Close() u, err := url.Parse(st.ts.URL) if err != nil { t.Fatal(err) } tr := &Transport{TLSClientConfig: tlsConfigInsecure} defer tr.CloseIdleConnections() c := &http.Client{Transport: tr} tests := []struct { req *http.Request want string }{ { req: &http.Request{ Method: "CONNECT", Header: http.Header{}, URL: u, }, want: u.Host, }, { req: &http.Request{ Method: "CONNECT", Header: http.Header{}, URL: u, Host: "example.com:123", }, want: "example.com:123", }, } for i, tt := range tests { res, err := c.Do(tt.req) if err != nil { t.Errorf("%d. RoundTrip = %v", i, err) continue } res.Body.Close() req := <-gotc if req.Method != "CONNECT" { t.Errorf("method = %q; want CONNECT", req.Method) } if req.Host != tt.want { t.Errorf("Host = %q; want %q", req.Host, tt.want) } if req.URL.Host != tt.want { t.Errorf("URL.Host = %q; want %q", req.URL.Host, tt.want) } } } type headerType int const ( noHeader headerType = iota // omitted oneHeader splitHeader // broken into continuation on purpose ) const ( f0 = noHeader f1 = oneHeader f2 = splitHeader d0 = false d1 = true ) // Test all 36 combinations of response frame orders: // (3 ways of 100-continue) * (2 ways of headers) * (2 ways of data) * (3 ways of trailers):func TestTransportResponsePattern_00f0(t *testing.T) { testTransportResponsePattern(h0, h1, false, h0) } // Generated by http://play.golang.org/p/SScqYKJYXd func TestTransportResPattern_c0h1d0t0(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f0) } func TestTransportResPattern_c0h1d0t1(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f1) } func TestTransportResPattern_c0h1d0t2(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f2) } func TestTransportResPattern_c0h1d1t0(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f0) } func TestTransportResPattern_c0h1d1t1(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f1) } func TestTransportResPattern_c0h1d1t2(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f2) } func TestTransportResPattern_c0h2d0t0(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f0) } func TestTransportResPattern_c0h2d0t1(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f1) } func TestTransportResPattern_c0h2d0t2(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f2) } func TestTransportResPattern_c0h2d1t0(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f0) } func TestTransportResPattern_c0h2d1t1(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f1) } func TestTransportResPattern_c0h2d1t2(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f2) } func TestTransportResPattern_c1h1d0t0(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f0) } func TestTransportResPattern_c1h1d0t1(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f1) } func TestTransportResPattern_c1h1d0t2(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f2) } func TestTransportResPattern_c1h1d1t0(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f0) } func TestTransportResPattern_c1h1d1t1(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f1) } func TestTransportResPattern_c1h1d1t2(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f2) } func TestTransportResPattern_c1h2d0t0(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f0) } func TestTransportResPattern_c1h2d0t1(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f1) } func TestTransportResPattern_c1h2d0t2(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f2) } func TestTransportResPattern_c1h2d1t0(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f0) } func TestTransportResPattern_c1h2d1t1(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f1) } func TestTransportResPattern_c1h2d1t2(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f2) } func TestTransportResPattern_c2h1d0t0(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f0) } func TestTransportResPattern_c2h1d0t1(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f1) } func TestTransportResPattern_c2h1d0t2(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f2) } func TestTransportResPattern_c2h1d1t0(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f0) } func TestTransportResPattern_c2h1d1t1(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f1) } func TestTransportResPattern_c2h1d1t2(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f2) } func TestTransportResPattern_c2h2d0t0(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f0) } func TestTransportResPattern_c2h2d0t1(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f1) } func TestTransportResPattern_c2h2d0t2(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f2) } func TestTransportResPattern_c2h2d1t0(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f0) } func TestTransportResPattern_c2h2d1t1(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f1) } func TestTransportResPattern_c2h2d1t2(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f2) } func testTransportResPattern(t *testing.T, expect100Continue, resHeader headerType, withData bool, trailers headerType) { const reqBody = "some request body" const resBody = "some response body" if resHeader == noHeader { // TODO: test 100-continue followed by immediate // server stream reset, without headers in the middle? panic("invalid combination") } ct := newClientTester(t) ct.client = func() error { req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader(reqBody)) if expect100Continue != noHeader { req.Header.Set("Expect", "100-continue") } res, err := ct.tr.RoundTrip(req) if err != nil { return fmt.Errorf("RoundTrip: %v", err) } defer res.Body.Close() if res.StatusCode != 200 { return fmt.Errorf("status code = %v; want 200", res.StatusCode) } slurp, err := ioutil.ReadAll(res.Body) if err != nil { return fmt.Errorf("Slurp: %v", err) } wantBody := resBody if !withData { wantBody = "" } if string(slurp) != wantBody { return fmt.Errorf("body = %q; want %q", slurp, wantBody) } if trailers == noHeader { if len(res.Trailer) > 0 { t.Errorf("Trailer = %v; want none", res.Trailer) } } else { want := http.Header{"Some-Trailer": {"some-value"}} if !reflect.DeepEqual(res.Trailer, want) { t.Errorf("Trailer = %v; want %v", res.Trailer, want) } } return nil } ct.server = func() error { ct.greet() var buf bytes.Buffer enc := hpack.NewEncoder(&buf) for { f, err := ct.fr.ReadFrame() if err != nil { return err } switch f := f.(type) { case *WindowUpdateFrame, *SettingsFrame: case *DataFrame: // ignore for now. case *HeadersFrame: endStream := false send := func(mode headerType) { hbf := buf.Bytes() switch mode { case oneHeader: ct.fr.WriteHeaders(HeadersFrameParam{ StreamID: f.StreamID, EndHeaders: true, EndStream: endStream, BlockFragment: hbf, }) case splitHeader: if len(hbf) < 2 { panic("too small") } ct.fr.WriteHeaders(HeadersFrameParam{ StreamID: f.StreamID, EndHeaders: false, EndStream: endStream, BlockFragment: hbf[:1], }) ct.fr.WriteContinuation(f.StreamID, true, hbf[1:]) default: panic("bogus mode") } } if expect100Continue != noHeader { buf.Reset() enc.WriteField(hpack.HeaderField{Name: ":status", Value: "100"}) send(expect100Continue) } // Response headers (1+ frames; 1 or 2 in this test, but never 0) { buf.Reset() enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) enc.WriteField(hpack.HeaderField{Name: "x-foo", Value: "blah"}) enc.WriteField(hpack.HeaderField{Name: "x-bar", Value: "more"}) if trailers != noHeader { enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "some-trailer"}) } endStream = withData == false && trailers == noHeader send(resHeader) } if withData { endStream = trailers == noHeader ct.fr.WriteData(f.StreamID, endStream, []byte(resBody)) } if trailers != noHeader { endStream = true buf.Reset() enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "some-value"}) send(trailers) } return nil } } } ct.run() } func TestTransportReceiveUndeclaredTrailer(t *testing.T) { ct := newClientTester(t) ct.client = func() error { req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) res, err := ct.tr.RoundTrip(req) if err != nil { return fmt.Errorf("RoundTrip: %v", err) } defer res.Body.Close() if res.StatusCode != 200 { return fmt.Errorf("status code = %v; want 200", res.StatusCode) } slurp, err := ioutil.ReadAll(res.Body) if err != nil { return fmt.Errorf("res.Body ReadAll error = %q, %v; want %v", slurp, err, nil) } if len(slurp) > 0 { return fmt.Errorf("body = %q; want nothing", slurp) } if _, ok := res.Trailer["Some-Trailer"]; !ok { return fmt.Errorf("expected Some-Trailer") } return nil } ct.server = func() error { ct.greet() var n int var hf *HeadersFrame for hf == nil && n < 10 { f, err := ct.fr.ReadFrame() if err != nil { return err } hf, _ = f.(*HeadersFrame) n++ } var buf bytes.Buffer enc := hpack.NewEncoder(&buf) // send headers without Trailer header enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) ct.fr.WriteHeaders(HeadersFrameParam{ StreamID: hf.StreamID, EndHeaders: true, EndStream: false, BlockFragment: buf.Bytes(), }) // send trailers buf.Reset() enc.WriteField(hpack.HeaderField{Name: "some-trailer", Value: "I'm an undeclared Trailer!"}) ct.fr.WriteHeaders(HeadersFrameParam{ StreamID: hf.StreamID, EndHeaders: true, EndStream: true, BlockFragment: buf.Bytes(), }) return nil } ct.run() } func TestTransportInvalidTrailer_Pseudo1(t *testing.T) { testTransportInvalidTrailer_Pseudo(t, oneHeader) } func TestTransportInvalidTrailer_Pseudo2(t *testing.T) { testTransportInvalidTrailer_Pseudo(t, splitHeader) } func testTransportInvalidTrailer_Pseudo(t *testing.T, trailers headerType) { testInvalidTrailer(t, trailers, errPseudoTrailers, func(enc *hpack.Encoder) { enc.WriteField(hpack.HeaderField{Name: ":colon", Value: "foo"}) enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"}) }) } func TestTransportInvalidTrailer_Capital1(t *testing.T) { testTransportInvalidTrailer_Capital(t, oneHeader) } func TestTransportInvalidTrailer_Capital2(t *testing.T) { testTransportInvalidTrailer_Capital(t, splitHeader) } func testTransportInvalidTrailer_Capital(t *testing.T, trailers headerType) { testInvalidTrailer(t, trailers, errInvalidHeaderKey, func(enc *hpack.Encoder) { enc.WriteField(hpack.HeaderField{Name: "foo", Value: "bar"}) enc.WriteField(hpack.HeaderField{Name: "Capital", Value: "bad"}) }) } func testInvalidTrailer(t *testing.T, trailers headerType, wantErr error, writeTrailer func(*hpack.Encoder)) { ct := newClientTester(t) ct.client = func() error { req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) res, err := ct.tr.RoundTrip(req) if err != nil { return fmt.Errorf("RoundTrip: %v", err) } defer res.Body.Close() if res.StatusCode != 200 { return fmt.Errorf("status code = %v; want 200", res.StatusCode) } slurp, err := ioutil.ReadAll(res.Body) if err != wantErr { return fmt.Errorf("res.Body ReadAll error = %q, %v; want %v", slurp, err, wantErr) } if len(slurp) > 0 { return fmt.Errorf("body = %q; want nothing", slurp) } return nil } ct.server = func() error { ct.greet() var buf bytes.Buffer enc := hpack.NewEncoder(&buf) for { f, err := ct.fr.ReadFrame() if err != nil { return err } switch f := f.(type) { case *HeadersFrame: var endStream bool send := func(mode headerType) { hbf := buf.Bytes() switch mode { case oneHeader: ct.fr.WriteHeaders(HeadersFrameParam{ StreamID: f.StreamID, EndHeaders: true, EndStream: endStream, BlockFragment: hbf, }) case splitHeader: if len(hbf) < 2 { panic("too small") } ct.fr.WriteHeaders(HeadersFrameParam{ StreamID: f.StreamID, EndHeaders: false, EndStream: endStream, BlockFragment: hbf[:1], }) ct.fr.WriteContinuation(f.StreamID, true, hbf[1:]) default: panic("bogus mode") } } // Response headers (1+ frames; 1 or 2 in this test, but never 0) { buf.Reset() enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) enc.WriteField(hpack.HeaderField{Name: "trailer", Value: "declared"}) endStream = false send(oneHeader) } // Trailers: { endStream = true buf.Reset() writeTrailer(enc) send(trailers) } return nil } } } ct.run() } func TestTransportChecksResponseHeaderListSize(t *testing.T) { ct := newClientTester(t) ct.client = func() error { req, _ := http.NewRequest("GET", "https://dummy.tld/", nil) res, err := ct.tr.RoundTrip(req) if err != errResponseHeaderListSize { if res != nil { res.Body.Close() } size := int64(0) for k, vv := range res.Header { for _, v := range vv { size += int64(len(k)) + int64(len(v)) + 32 } } return fmt.Errorf("RoundTrip Error = %v (and %d bytes of response headers); want errResponseHeaderListSize", err, size) } return nil } ct.server = func() error { ct.greet() var buf bytes.Buffer enc := hpack.NewEncoder(&buf) for { f, err := ct.fr.ReadFrame() if err != nil { return err } switch f := f.(type) { case *HeadersFrame: enc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"}) large := strings.Repeat("a", 1<<10) for i := 0; i < 5042; i++ { enc.WriteField(hpack.HeaderField{Name: large, Value: large}) } if size, want := buf.Len(), 6329; size != want { // Note: this number might change if // our hpack implementation // changes. That's fine. This is // just a sanity check that our // response can fit in a single // header block fragment frame. return fmt.Errorf("encoding over 10MB of duplicate keypairs took %d bytes; expected %d", size, want) } ct.fr.WriteHeaders(HeadersFrameParam{ StreamID: f.StreamID, EndHeaders: true, EndStream: true, BlockFragment: buf.Bytes(), }) return nil } } } ct.run() } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/write.go000066400000000000000000000145411264464372400231670ustar00rootroot00000000000000// Copyright 2014 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 http2 import ( "bytes" "fmt" "log" "net/http" "sort" "time" "golang.org/x/net/http2/hpack" ) // writeFramer is implemented by any type that is used to write frames. type writeFramer interface { writeFrame(writeContext) error } // writeContext is the interface needed by the various frame writer // types below. All the writeFrame methods below are scheduled via the // frame writing scheduler (see writeScheduler in writesched.go). // // This interface is implemented by *serverConn. // // TODO: decide whether to a) use this in the client code (which didn't // end up using this yet, because it has a simpler design, not // currently implementing priorities), or b) delete this and // make the server code a bit more concrete. type writeContext interface { Framer() *Framer Flush() error CloseConn() error // HeaderEncoder returns an HPACK encoder that writes to the // returned buffer. HeaderEncoder() (*hpack.Encoder, *bytes.Buffer) } // endsStream reports whether the given frame writer w will locally // close the stream. func endsStream(w writeFramer) bool { switch v := w.(type) { case *writeData: return v.endStream case *writeResHeaders: return v.endStream case nil: // This can only happen if the caller reuses w after it's // been intentionally nil'ed out to prevent use. Keep this // here to catch future refactoring breaking it. panic("endsStream called on nil writeFramer") } return false } type flushFrameWriter struct{} func (flushFrameWriter) writeFrame(ctx writeContext) error { return ctx.Flush() } type writeSettings []Setting func (s writeSettings) writeFrame(ctx writeContext) error { return ctx.Framer().WriteSettings([]Setting(s)...) } type writeGoAway struct { maxStreamID uint32 code ErrCode } func (p *writeGoAway) writeFrame(ctx writeContext) error { err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil) if p.code != 0 { ctx.Flush() // ignore error: we're hanging up on them anyway time.Sleep(50 * time.Millisecond) ctx.CloseConn() } return err } type writeData struct { streamID uint32 p []byte endStream bool } func (w *writeData) String() string { return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", w.streamID, len(w.p), w.endStream) } func (w *writeData) writeFrame(ctx writeContext) error { return ctx.Framer().WriteData(w.streamID, w.endStream, w.p) } // handlerPanicRST is the message sent from handler goroutines when // the handler panics. type handlerPanicRST struct { StreamID uint32 } func (hp handlerPanicRST) writeFrame(ctx writeContext) error { return ctx.Framer().WriteRSTStream(hp.StreamID, ErrCodeInternal) } func (se StreamError) writeFrame(ctx writeContext) error { return ctx.Framer().WriteRSTStream(se.StreamID, se.Code) } type writePingAck struct{ pf *PingFrame } func (w writePingAck) writeFrame(ctx writeContext) error { return ctx.Framer().WritePing(true, w.pf.Data) } type writeSettingsAck struct{} func (writeSettingsAck) writeFrame(ctx writeContext) error { return ctx.Framer().WriteSettingsAck() } // writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames // for HTTP response headers or trailers from a server handler. type writeResHeaders struct { streamID uint32 httpResCode int // 0 means no ":status" line h http.Header // may be nil trailers []string // if non-nil, which keys of h to write. nil means all. endStream bool date string contentType string contentLength string } func encKV(enc *hpack.Encoder, k, v string) { if VerboseLogs { log.Printf("http2: server encoding header %q = %q", k, v) } enc.WriteField(hpack.HeaderField{Name: k, Value: v}) } func (w *writeResHeaders) writeFrame(ctx writeContext) error { enc, buf := ctx.HeaderEncoder() buf.Reset() if w.httpResCode != 0 { encKV(enc, ":status", httpCodeString(w.httpResCode)) } encodeHeaders(enc, w.h, w.trailers) if w.contentType != "" { encKV(enc, "content-type", w.contentType) } if w.contentLength != "" { encKV(enc, "content-length", w.contentLength) } if w.date != "" { encKV(enc, "date", w.date) } headerBlock := buf.Bytes() if len(headerBlock) == 0 && w.trailers == nil { panic("unexpected empty hpack") } // For now we're lazy and just pick the minimum MAX_FRAME_SIZE // that all peers must support (16KB). Later we could care // more and send larger frames if the peer advertised it, but // there's little point. Most headers are small anyway (so we // generally won't have CONTINUATION frames), and extra frames // only waste 9 bytes anyway. const maxFrameSize = 16384 first := true for len(headerBlock) > 0 { frag := headerBlock if len(frag) > maxFrameSize { frag = frag[:maxFrameSize] } headerBlock = headerBlock[len(frag):] endHeaders := len(headerBlock) == 0 var err error if first { first = false err = ctx.Framer().WriteHeaders(HeadersFrameParam{ StreamID: w.streamID, BlockFragment: frag, EndStream: w.endStream, EndHeaders: endHeaders, }) } else { err = ctx.Framer().WriteContinuation(w.streamID, endHeaders, frag) } if err != nil { return err } } return nil } type write100ContinueHeadersFrame struct { streamID uint32 } func (w write100ContinueHeadersFrame) writeFrame(ctx writeContext) error { enc, buf := ctx.HeaderEncoder() buf.Reset() encKV(enc, ":status", "100") return ctx.Framer().WriteHeaders(HeadersFrameParam{ StreamID: w.streamID, BlockFragment: buf.Bytes(), EndStream: false, EndHeaders: true, }) } type writeWindowUpdate struct { streamID uint32 // or 0 for conn-level n uint32 } func (wu writeWindowUpdate) writeFrame(ctx writeContext) error { return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n) } func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) { // TODO: garbage. pool sorters like http1? hot path for 1 key? if keys == nil { keys = make([]string, 0, len(h)) for k := range h { keys = append(keys, k) } sort.Strings(keys) } for _, k := range keys { vv := h[k] k = lowerHeader(k) isTE := k == "transfer-encoding" for _, v := range vv { // TODO: more of "8.1.2.2 Connection-Specific Header Fields" if isTE && v != "trailers" { continue } encKV(enc, k, v) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/writesched.go000066400000000000000000000163661264464372400242050ustar00rootroot00000000000000// Copyright 2014 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 http2 import "fmt" // frameWriteMsg is a request to write a frame. type frameWriteMsg struct { // write is the interface value that does the writing, once the // writeScheduler (below) has decided to select this frame // to write. The write functions are all defined in write.go. write writeFramer stream *stream // used for prioritization. nil for non-stream frames. // done, if non-nil, must be a buffered channel with space for // 1 message and is sent the return value from write (or an // earlier error) when the frame has been written. done chan error } // for debugging only: func (wm frameWriteMsg) String() string { var streamID uint32 if wm.stream != nil { streamID = wm.stream.id } var des string if s, ok := wm.write.(fmt.Stringer); ok { des = s.String() } else { des = fmt.Sprintf("%T", wm.write) } return fmt.Sprintf("[frameWriteMsg stream=%d, ch=%v, type: %v]", streamID, wm.done != nil, des) } // writeScheduler tracks pending frames to write, priorities, and decides // the next one to use. It is not thread-safe. type writeScheduler struct { // zero are frames not associated with a specific stream. // They're sent before any stream-specific freams. zero writeQueue // maxFrameSize is the maximum size of a DATA frame // we'll write. Must be non-zero and between 16K-16M. maxFrameSize uint32 // sq contains the stream-specific queues, keyed by stream ID. // when a stream is idle, it's deleted from the map. sq map[uint32]*writeQueue // canSend is a slice of memory that's reused between frame // scheduling decisions to hold the list of writeQueues (from sq) // which have enough flow control data to send. After canSend is // built, the best is selected. canSend []*writeQueue // pool of empty queues for reuse. queuePool []*writeQueue } func (ws *writeScheduler) putEmptyQueue(q *writeQueue) { if len(q.s) != 0 { panic("queue must be empty") } ws.queuePool = append(ws.queuePool, q) } func (ws *writeScheduler) getEmptyQueue() *writeQueue { ln := len(ws.queuePool) if ln == 0 { return new(writeQueue) } q := ws.queuePool[ln-1] ws.queuePool = ws.queuePool[:ln-1] return q } func (ws *writeScheduler) empty() bool { return ws.zero.empty() && len(ws.sq) == 0 } func (ws *writeScheduler) add(wm frameWriteMsg) { st := wm.stream if st == nil { ws.zero.push(wm) } else { ws.streamQueue(st.id).push(wm) } } func (ws *writeScheduler) streamQueue(streamID uint32) *writeQueue { if q, ok := ws.sq[streamID]; ok { return q } if ws.sq == nil { ws.sq = make(map[uint32]*writeQueue) } q := ws.getEmptyQueue() ws.sq[streamID] = q return q } // take returns the most important frame to write and removes it from the scheduler. // It is illegal to call this if the scheduler is empty or if there are no connection-level // flow control bytes available. func (ws *writeScheduler) take() (wm frameWriteMsg, ok bool) { if ws.maxFrameSize == 0 { panic("internal error: ws.maxFrameSize not initialized or invalid") } // If there any frames not associated with streams, prefer those first. // These are usually SETTINGS, etc. if !ws.zero.empty() { return ws.zero.shift(), true } if len(ws.sq) == 0 { return } // Next, prioritize frames on streams that aren't DATA frames (no cost). for id, q := range ws.sq { if q.firstIsNoCost() { return ws.takeFrom(id, q) } } // Now, all that remains are DATA frames with non-zero bytes to // send. So pick the best one. if len(ws.canSend) != 0 { panic("should be empty") } for _, q := range ws.sq { if n := ws.streamWritableBytes(q); n > 0 { ws.canSend = append(ws.canSend, q) } } if len(ws.canSend) == 0 { return } defer ws.zeroCanSend() // TODO: find the best queue q := ws.canSend[0] return ws.takeFrom(q.streamID(), q) } // zeroCanSend is defered from take. func (ws *writeScheduler) zeroCanSend() { for i := range ws.canSend { ws.canSend[i] = nil } ws.canSend = ws.canSend[:0] } // streamWritableBytes returns the number of DATA bytes we could write // from the given queue's stream, if this stream/queue were // selected. It is an error to call this if q's head isn't a // *writeData. func (ws *writeScheduler) streamWritableBytes(q *writeQueue) int32 { wm := q.head() ret := wm.stream.flow.available() // max we can write if ret == 0 { return 0 } if int32(ws.maxFrameSize) < ret { ret = int32(ws.maxFrameSize) } if ret == 0 { panic("internal error: ws.maxFrameSize not initialized or invalid") } wd := wm.write.(*writeData) if len(wd.p) < int(ret) { ret = int32(len(wd.p)) } return ret } func (ws *writeScheduler) takeFrom(id uint32, q *writeQueue) (wm frameWriteMsg, ok bool) { wm = q.head() // If the first item in this queue costs flow control tokens // and we don't have enough, write as much as we can. if wd, ok := wm.write.(*writeData); ok && len(wd.p) > 0 { allowed := wm.stream.flow.available() // max we can write if allowed == 0 { // No quota available. Caller can try the next stream. return frameWriteMsg{}, false } if int32(ws.maxFrameSize) < allowed { allowed = int32(ws.maxFrameSize) } // TODO: further restrict the allowed size, because even if // the peer says it's okay to write 16MB data frames, we might // want to write smaller ones to properly weight competing // streams' priorities. if len(wd.p) > int(allowed) { wm.stream.flow.take(allowed) chunk := wd.p[:allowed] wd.p = wd.p[allowed:] // Make up a new write message of a valid size, rather // than shifting one off the queue. return frameWriteMsg{ stream: wm.stream, write: &writeData{ streamID: wd.streamID, p: chunk, // even if the original had endStream set, there // arebytes remaining because len(wd.p) > allowed, // so we know endStream is false: endStream: false, }, // our caller is blocking on the final DATA frame, not // these intermediates, so no need to wait: done: nil, }, true } wm.stream.flow.take(int32(len(wd.p))) } q.shift() if q.empty() { ws.putEmptyQueue(q) delete(ws.sq, id) } return wm, true } func (ws *writeScheduler) forgetStream(id uint32) { q, ok := ws.sq[id] if !ok { return } delete(ws.sq, id) // But keep it for others later. for i := range q.s { q.s[i] = frameWriteMsg{} } q.s = q.s[:0] ws.putEmptyQueue(q) } type writeQueue struct { s []frameWriteMsg } // streamID returns the stream ID for a non-empty stream-specific queue. func (q *writeQueue) streamID() uint32 { return q.s[0].stream.id } func (q *writeQueue) empty() bool { return len(q.s) == 0 } func (q *writeQueue) push(wm frameWriteMsg) { q.s = append(q.s, wm) } // head returns the next item that would be removed by shift. func (q *writeQueue) head() frameWriteMsg { if len(q.s) == 0 { panic("invalid use of queue") } return q.s[0] } func (q *writeQueue) shift() frameWriteMsg { if len(q.s) == 0 { panic("invalid use of queue") } wm := q.s[0] // TODO: less copy-happy queue. copy(q.s, q.s[1:]) q.s[len(q.s)-1] = frameWriteMsg{} q.s = q.s[:len(q.s)-1] return wm } func (q *writeQueue) firstIsNoCost() bool { if df, ok := q.s[0].write.(*writeData); ok { return len(df.p) == 0 } return true } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/http2/z_spec_test.go000066400000000000000000000164221264464372400243570ustar00rootroot00000000000000// Copyright 2014 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 http2 import ( "bytes" "encoding/xml" "flag" "fmt" "io" "os" "reflect" "regexp" "sort" "strconv" "strings" "sync" "testing" ) var coverSpec = flag.Bool("coverspec", false, "Run spec coverage tests") // The global map of sentence coverage for the http2 spec. var defaultSpecCoverage specCoverage var loadSpecOnce sync.Once func loadSpec() { if f, err := os.Open("testdata/draft-ietf-httpbis-http2.xml"); err != nil { panic(err) } else { defaultSpecCoverage = readSpecCov(f) f.Close() } } // covers marks all sentences for section sec in defaultSpecCoverage. Sentences not // "covered" will be included in report outputed by TestSpecCoverage. func covers(sec, sentences string) { loadSpecOnce.Do(loadSpec) defaultSpecCoverage.cover(sec, sentences) } type specPart struct { section string sentence string } func (ss specPart) Less(oo specPart) bool { atoi := func(s string) int { n, err := strconv.Atoi(s) if err != nil { panic(err) } return n } a := strings.Split(ss.section, ".") b := strings.Split(oo.section, ".") for len(a) > 0 { if len(b) == 0 { return false } x, y := atoi(a[0]), atoi(b[0]) if x == y { a, b = a[1:], b[1:] continue } return x < y } if len(b) > 0 { return true } return false } type bySpecSection []specPart func (a bySpecSection) Len() int { return len(a) } func (a bySpecSection) Less(i, j int) bool { return a[i].Less(a[j]) } func (a bySpecSection) Swap(i, j int) { a[i], a[j] = a[j], a[i] } type specCoverage struct { coverage map[specPart]bool d *xml.Decoder } func joinSection(sec []int) string { s := fmt.Sprintf("%d", sec[0]) for _, n := range sec[1:] { s = fmt.Sprintf("%s.%d", s, n) } return s } func (sc specCoverage) readSection(sec []int) { var ( buf = new(bytes.Buffer) sub = 0 ) for { tk, err := sc.d.Token() if err != nil { if err == io.EOF { return } panic(err) } switch v := tk.(type) { case xml.StartElement: if skipElement(v) { if err := sc.d.Skip(); err != nil { panic(err) } if v.Name.Local == "section" { sub++ } break } switch v.Name.Local { case "section": sub++ sc.readSection(append(sec, sub)) case "xref": buf.Write(sc.readXRef(v)) } case xml.CharData: if len(sec) == 0 { break } buf.Write(v) case xml.EndElement: if v.Name.Local == "section" { sc.addSentences(joinSection(sec), buf.String()) return } } } } func (sc specCoverage) readXRef(se xml.StartElement) []byte { var b []byte for { tk, err := sc.d.Token() if err != nil { panic(err) } switch v := tk.(type) { case xml.CharData: if b != nil { panic("unexpected CharData") } b = []byte(string(v)) case xml.EndElement: if v.Name.Local != "xref" { panic("expected ") } if b != nil { return b } sig := attrSig(se) switch sig { case "target": return []byte(fmt.Sprintf("[%s]", attrValue(se, "target"))) case "fmt-of,rel,target", "fmt-,,rel,target": return []byte(fmt.Sprintf("[%s, %s]", attrValue(se, "target"), attrValue(se, "rel"))) case "fmt-of,sec,target", "fmt-,,sec,target": return []byte(fmt.Sprintf("[section %s of %s]", attrValue(se, "sec"), attrValue(se, "target"))) case "fmt-of,rel,sec,target": return []byte(fmt.Sprintf("[section %s of %s, %s]", attrValue(se, "sec"), attrValue(se, "target"), attrValue(se, "rel"))) default: panic(fmt.Sprintf("unknown attribute signature %q in %#v", sig, fmt.Sprintf("%#v", se))) } default: panic(fmt.Sprintf("unexpected tag %q", v)) } } } var skipAnchor = map[string]bool{ "intro": true, "Overview": true, } var skipTitle = map[string]bool{ "Acknowledgements": true, "Change Log": true, "Document Organization": true, "Conventions and Terminology": true, } func skipElement(s xml.StartElement) bool { switch s.Name.Local { case "artwork": return true case "section": for _, attr := range s.Attr { switch attr.Name.Local { case "anchor": if skipAnchor[attr.Value] || strings.HasPrefix(attr.Value, "changes.since.") { return true } case "title": if skipTitle[attr.Value] { return true } } } } return false } func readSpecCov(r io.Reader) specCoverage { sc := specCoverage{ coverage: map[specPart]bool{}, d: xml.NewDecoder(r)} sc.readSection(nil) return sc } func (sc specCoverage) addSentences(sec string, sentence string) { for _, s := range parseSentences(sentence) { sc.coverage[specPart{sec, s}] = false } } func (sc specCoverage) cover(sec string, sentence string) { for _, s := range parseSentences(sentence) { p := specPart{sec, s} if _, ok := sc.coverage[p]; !ok { panic(fmt.Sprintf("Not found in spec: %q, %q", sec, s)) } sc.coverage[specPart{sec, s}] = true } } var whitespaceRx = regexp.MustCompile(`\s+`) func parseSentences(sens string) []string { sens = strings.TrimSpace(sens) if sens == "" { return nil } ss := strings.Split(whitespaceRx.ReplaceAllString(sens, " "), ". ") for i, s := range ss { s = strings.TrimSpace(s) if !strings.HasSuffix(s, ".") { s += "." } ss[i] = s } return ss } func TestSpecParseSentences(t *testing.T) { tests := []struct { ss string want []string }{ {"Sentence 1. Sentence 2.", []string{ "Sentence 1.", "Sentence 2.", }}, {"Sentence 1. \nSentence 2.\tSentence 3.", []string{ "Sentence 1.", "Sentence 2.", "Sentence 3.", }}, } for i, tt := range tests { got := parseSentences(tt.ss) if !reflect.DeepEqual(got, tt.want) { t.Errorf("%d: got = %q, want %q", i, got, tt.want) } } } func TestSpecCoverage(t *testing.T) { if !*coverSpec { t.Skip() } loadSpecOnce.Do(loadSpec) var ( list []specPart cv = defaultSpecCoverage.coverage total = len(cv) complete = 0 ) for sp, touched := range defaultSpecCoverage.coverage { if touched { complete++ } else { list = append(list, sp) } } sort.Stable(bySpecSection(list)) if testing.Short() && len(list) > 5 { list = list[:5] } for _, p := range list { t.Errorf("\tSECTION %s: %s", p.section, p.sentence) } t.Logf("%d/%d (%d%%) sentances covered", complete, total, (complete/total)*100) } func attrSig(se xml.StartElement) string { var names []string for _, attr := range se.Attr { if attr.Name.Local == "fmt" { names = append(names, "fmt-"+attr.Value) } else { names = append(names, attr.Name.Local) } } sort.Strings(names) return strings.Join(names, ",") } func attrValue(se xml.StartElement, attr string) string { for _, a := range se.Attr { if a.Name.Local == attr { return a.Value } } panic("unknown attribute " + attr) } func TestSpecPartLess(t *testing.T) { tests := []struct { sec1, sec2 string want bool }{ {"6.2.1", "6.2", false}, {"6.2", "6.2.1", true}, {"6.10", "6.10.1", true}, {"6.10", "6.1.1", false}, // 10, not 1 {"6.1", "6.1", false}, // equal, so not less } for _, tt := range tests { got := (specPart{tt.sec1, "foo"}).Less(specPart{tt.sec2, "foo"}) if got != tt.want { t.Errorf("Less(%q, %q) = %v; want %v", tt.sec1, tt.sec2, got, tt.want) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/000077500000000000000000000000001264464372400213705ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/dstunreach.go000066400000000000000000000021651264464372400240630ustar00rootroot00000000000000// Copyright 2014 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 icmp // A DstUnreach represents an ICMP destination unreachable message // body. type DstUnreach struct { Data []byte // data, known as original datagram field Extensions []Extension // extensions } // Len implements the Len method of MessageBody interface. func (p *DstUnreach) Len(proto int) int { if p == nil { return 0 } l, _ := multipartMessageBodyDataLen(proto, p.Data, p.Extensions) return 4 + l } // Marshal implements the Marshal method of MessageBody interface. func (p *DstUnreach) Marshal(proto int) ([]byte, error) { return marshalMultipartMessageBody(proto, p.Data, p.Extensions) } // parseDstUnreach parses b as an ICMP destination unreachable message // body. func parseDstUnreach(proto int, b []byte) (MessageBody, error) { if len(b) < 4 { return nil, errMessageTooShort } p := &DstUnreach{} var err error p.Data, p.Extensions, err = parseMultipartMessageBody(proto, b) if err != nil { return nil, err } return p, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/echo.go000066400000000000000000000021611264464372400226350ustar00rootroot00000000000000// Copyright 2012 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 icmp // An Echo represents an ICMP echo request or reply message body. type Echo struct { ID int // identifier Seq int // sequence number Data []byte // data } // Len implements the Len method of MessageBody interface. func (p *Echo) Len(proto int) int { if p == nil { return 0 } return 4 + len(p.Data) } // Marshal implements the Marshal method of MessageBody interface. func (p *Echo) Marshal(proto int) ([]byte, error) { b := make([]byte, 4+len(p.Data)) b[0], b[1] = byte(p.ID>>8), byte(p.ID) b[2], b[3] = byte(p.Seq>>8), byte(p.Seq) copy(b[4:], p.Data) return b, nil } // parseEcho parses b as an ICMP echo request or reply message body. func parseEcho(proto int, b []byte) (MessageBody, error) { bodyLen := len(b) if bodyLen < 4 { return nil, errMessageTooShort } p := &Echo{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])} if bodyLen > 4 { p.Data = make([]byte, bodyLen-4) copy(p.Data, b[4:]) } return p, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/endpoint.go000066400000000000000000000051701264464372400235420ustar00rootroot00000000000000// Copyright 2014 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 icmp import ( "net" "runtime" "syscall" "time" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" ) var _ net.PacketConn = &PacketConn{} // A PacketConn represents a packet network endpoint that uses either // ICMPv4 or ICMPv6. type PacketConn struct { c net.PacketConn p4 *ipv4.PacketConn p6 *ipv6.PacketConn } func (c *PacketConn) ok() bool { return c != nil && c.c != nil } // IPv4PacketConn returns the ipv4.PacketConn of c. // It returns nil when c is not created as the endpoint for ICMPv4. func (c *PacketConn) IPv4PacketConn() *ipv4.PacketConn { if !c.ok() { return nil } return c.p4 } // IPv6PacketConn returns the ipv6.PacketConn of c. // It returns nil when c is not created as the endpoint for ICMPv6. func (c *PacketConn) IPv6PacketConn() *ipv6.PacketConn { if !c.ok() { return nil } return c.p6 } // ReadFrom reads an ICMP message from the connection. func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { if !c.ok() { return 0, nil, syscall.EINVAL } // Please be informed that ipv4.NewPacketConn enables // IP_STRIPHDR option by default on Darwin. // See golang.org/issue/9395 for futher information. if runtime.GOOS == "darwin" && c.p4 != nil { n, _, peer, err := c.p4.ReadFrom(b) return n, peer, err } return c.c.ReadFrom(b) } // WriteTo writes the ICMP message b to dst. // Dst must be net.UDPAddr when c is a non-privileged // datagram-oriented ICMP endpoint. Otherwise it must be net.IPAddr. func (c *PacketConn) WriteTo(b []byte, dst net.Addr) (int, error) { if !c.ok() { return 0, syscall.EINVAL } return c.c.WriteTo(b, dst) } // Close closes the endpoint. func (c *PacketConn) Close() error { if !c.ok() { return syscall.EINVAL } return c.c.Close() } // LocalAddr returns the local network address. func (c *PacketConn) LocalAddr() net.Addr { if !c.ok() { return nil } return c.c.LocalAddr() } // SetDeadline sets the read and write deadlines associated with the // endpoint. func (c *PacketConn) SetDeadline(t time.Time) error { if !c.ok() { return syscall.EINVAL } return c.c.SetDeadline(t) } // SetReadDeadline sets the read deadline associated with the // endpoint. func (c *PacketConn) SetReadDeadline(t time.Time) error { if !c.ok() { return syscall.EINVAL } return c.c.SetReadDeadline(t) } // SetWriteDeadline sets the write deadline associated with the // endpoint. func (c *PacketConn) SetWriteDeadline(t time.Time) error { if !c.ok() { return syscall.EINVAL } return c.c.SetWriteDeadline(t) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/example_test.go000066400000000000000000000024341264464372400244140ustar00rootroot00000000000000// Copyright 2014 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 icmp_test import ( "log" "net" "os" "runtime" "golang.org/x/net/icmp" "golang.org/x/net/ipv6" ) func ExamplePacketConn_nonPrivilegedPing() { switch runtime.GOOS { case "darwin": case "linux": log.Println("you may need to adjust the net.ipv4.ping_group_range kernel state") default: log.Println("not supported on", runtime.GOOS) return } c, err := icmp.ListenPacket("udp6", "fe80::1%en0") if err != nil { log.Fatal(err) } defer c.Close() wm := icmp.Message{ Type: ipv6.ICMPTypeEchoRequest, Code: 0, Body: &icmp.Echo{ ID: os.Getpid() & 0xffff, Seq: 1, Data: []byte("HELLO-R-U-THERE"), }, } wb, err := wm.Marshal(nil) if err != nil { log.Fatal(err) } if _, err := c.WriteTo(wb, &net.UDPAddr{IP: net.ParseIP("ff02::1"), Zone: "en0"}); err != nil { log.Fatal(err) } rb := make([]byte, 1500) n, peer, err := c.ReadFrom(rb) if err != nil { log.Fatal(err) } rm, err := icmp.ParseMessage(58, rb[:n]) if err != nil { log.Fatal(err) } switch rm.Type { case ipv6.ICMPTypeEchoReply: log.Printf("got reflection from %v", peer) default: log.Printf("got %+v; want echo reply", rm) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/extension.go000066400000000000000000000043611264464372400237370ustar00rootroot00000000000000// Copyright 2015 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 icmp // An Extension represents an ICMP extension. type Extension interface { // Len returns the length of ICMP extension. // Proto must be either the ICMPv4 or ICMPv6 protocol number. Len(proto int) int // Marshal returns the binary encoding of ICMP extension. // Proto must be either the ICMPv4 or ICMPv6 protocol number. Marshal(proto int) ([]byte, error) } const extensionVersion = 2 func validExtensionHeader(b []byte) bool { v := int(b[0]&0xf0) >> 4 s := uint16(b[2])<<8 | uint16(b[3]) if s != 0 { s = checksum(b) } if v != extensionVersion || s != 0 { return false } return true } // parseExtensions parses b as a list of ICMP extensions. // The length attribute l must be the length attribute field in // received icmp messages. // // It will return a list of ICMP extensions and an adjusted length // attribute that represents the length of the padded original // datagram field. Otherwise, it returns an error. func parseExtensions(b []byte, l int) ([]Extension, int, error) { // Still a lot of non-RFC 4884 compliant implementations are // out there. Set the length attribute l to 128 when it looks // inappropriate for backwards compatibility. // // A minimal extension at least requires 8 octets; 4 octets // for an extension header, and 4 octets for a single object // header. // // See RFC 4884 for further information. if 128 > l || l+8 > len(b) { l = 128 } if l+8 > len(b) { return nil, -1, errNoExtension } if !validExtensionHeader(b[l:]) { if l == 128 { return nil, -1, errNoExtension } l = 128 if !validExtensionHeader(b[l:]) { return nil, -1, errNoExtension } } var exts []Extension for b = b[l+4:]; len(b) >= 4; { ol := int(b[0])<<8 | int(b[1]) if 4 > ol || ol > len(b) { break } switch b[2] { case classMPLSLabelStack: ext, err := parseMPLSLabelStack(b[:ol]) if err != nil { return nil, -1, err } exts = append(exts, ext) case classInterfaceInfo: ext, err := parseInterfaceInfo(b[:ol]) if err != nil { return nil, -1, err } exts = append(exts, ext) } b = b[ol:] } return exts, l, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/extension_test.go000066400000000000000000000134201264464372400247720ustar00rootroot00000000000000// Copyright 2015 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 icmp import ( "net" "reflect" "testing" "golang.org/x/net/internal/iana" ) var marshalAndParseExtensionTests = []struct { proto int hdr []byte obj []byte exts []Extension }{ // MPLS label stack with no label { proto: iana.ProtocolICMP, hdr: []byte{ 0x20, 0x00, 0x00, 0x00, }, obj: []byte{ 0x00, 0x04, 0x01, 0x01, }, exts: []Extension{ &MPLSLabelStack{ Class: classMPLSLabelStack, Type: typeIncomingMPLSLabelStack, }, }, }, // MPLS label stack with a single label { proto: iana.ProtocolIPv6ICMP, hdr: []byte{ 0x20, 0x00, 0x00, 0x00, }, obj: []byte{ 0x00, 0x08, 0x01, 0x01, 0x03, 0xe8, 0xe9, 0xff, }, exts: []Extension{ &MPLSLabelStack{ Class: classMPLSLabelStack, Type: typeIncomingMPLSLabelStack, Labels: []MPLSLabel{ { Label: 16014, TC: 0x4, S: true, TTL: 255, }, }, }, }, }, // MPLS label stack with multiple labels { proto: iana.ProtocolICMP, hdr: []byte{ 0x20, 0x00, 0x00, 0x00, }, obj: []byte{ 0x00, 0x0c, 0x01, 0x01, 0x03, 0xe8, 0xde, 0xfe, 0x03, 0xe8, 0xe1, 0xff, }, exts: []Extension{ &MPLSLabelStack{ Class: classMPLSLabelStack, Type: typeIncomingMPLSLabelStack, Labels: []MPLSLabel{ { Label: 16013, TC: 0x7, S: false, TTL: 254, }, { Label: 16014, TC: 0, S: true, TTL: 255, }, }, }, }, }, // Interface information with no attribute { proto: iana.ProtocolICMP, hdr: []byte{ 0x20, 0x00, 0x00, 0x00, }, obj: []byte{ 0x00, 0x04, 0x02, 0x00, }, exts: []Extension{ &InterfaceInfo{ Class: classInterfaceInfo, }, }, }, // Interface information with ifIndex and name { proto: iana.ProtocolICMP, hdr: []byte{ 0x20, 0x00, 0x00, 0x00, }, obj: []byte{ 0x00, 0x10, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x08, byte('e'), byte('n'), byte('1'), byte('0'), byte('1'), 0x00, 0x00, }, exts: []Extension{ &InterfaceInfo{ Class: classInterfaceInfo, Type: 0x0a, Interface: &net.Interface{ Index: 16, Name: "en101", }, }, }, }, // Interface information with ifIndex, IPAddr, name and MTU { proto: iana.ProtocolIPv6ICMP, hdr: []byte{ 0x20, 0x00, 0x00, 0x00, }, obj: []byte{ 0x00, 0x28, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x00, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, byte('e'), byte('n'), byte('1'), byte('0'), byte('1'), 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, }, exts: []Extension{ &InterfaceInfo{ Class: classInterfaceInfo, Type: 0x0f, Interface: &net.Interface{ Index: 15, Name: "en101", MTU: 8192, }, Addr: &net.IPAddr{ IP: net.ParseIP("fe80::1"), Zone: "en101", }, }, }, }, } func TestMarshalAndParseExtension(t *testing.T) { for i, tt := range marshalAndParseExtensionTests { for j, ext := range tt.exts { var err error var b []byte switch ext := ext.(type) { case *MPLSLabelStack: b, err = ext.Marshal(tt.proto) if err != nil { t.Errorf("#%v/%v: %v", i, j, err) continue } case *InterfaceInfo: b, err = ext.Marshal(tt.proto) if err != nil { t.Errorf("#%v/%v: %v", i, j, err) continue } } if !reflect.DeepEqual(b, tt.obj) { t.Errorf("#%v/%v: got %#v; want %#v", i, j, b, tt.obj) continue } } for j, wire := range []struct { data []byte // original datagram inlattr int // length of padded original datagram, a hint outlattr int // length of padded original datagram, a want err error }{ {nil, 0, -1, errNoExtension}, {make([]byte, 127), 128, -1, errNoExtension}, {make([]byte, 128), 127, -1, errNoExtension}, {make([]byte, 128), 128, -1, errNoExtension}, {make([]byte, 128), 129, -1, errNoExtension}, {append(make([]byte, 128), append(tt.hdr, tt.obj...)...), 127, 128, nil}, {append(make([]byte, 128), append(tt.hdr, tt.obj...)...), 128, 128, nil}, {append(make([]byte, 128), append(tt.hdr, tt.obj...)...), 129, 128, nil}, {append(make([]byte, 512), append(tt.hdr, tt.obj...)...), 511, -1, errNoExtension}, {append(make([]byte, 512), append(tt.hdr, tt.obj...)...), 512, 512, nil}, {append(make([]byte, 512), append(tt.hdr, tt.obj...)...), 513, -1, errNoExtension}, } { exts, l, err := parseExtensions(wire.data, wire.inlattr) if err != wire.err { t.Errorf("#%v/%v: got %v; want %v", i, j, err, wire.err) continue } if wire.err != nil { continue } if l != wire.outlattr { t.Errorf("#%v/%v: got %v; want %v", i, j, l, wire.outlattr) } if !reflect.DeepEqual(exts, tt.exts) { for j, ext := range exts { switch ext := ext.(type) { case *MPLSLabelStack: want := tt.exts[j].(*MPLSLabelStack) t.Errorf("#%v/%v: got %#v; want %#v", i, j, ext, want) case *InterfaceInfo: want := tt.exts[j].(*InterfaceInfo) t.Errorf("#%v/%v: got %#v; want %#v", i, j, ext, want) } } continue } } } } var parseInterfaceNameTests = []struct { b []byte error }{ {[]byte{0, 'e', 'n', '0'}, errInvalidExtension}, {[]byte{4, 'e', 'n', '0'}, nil}, {[]byte{7, 'e', 'n', '0', 0xff, 0xff, 0xff, 0xff}, errInvalidExtension}, {[]byte{8, 'e', 'n', '0', 0xff, 0xff, 0xff}, errMessageTooShort}, } func TestParseInterfaceName(t *testing.T) { ifi := InterfaceInfo{Interface: &net.Interface{}} for i, tt := range parseInterfaceNameTests { if _, err := ifi.parseName(tt.b); err != tt.error { t.Errorf("#%d: got %v; want %v", i, err, tt.error) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/helper_posix.go000066400000000000000000000030661264464372400244250ustar00rootroot00000000000000// Copyright 2014 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. // +build darwin dragonfly freebsd linux netbsd openbsd solaris windows package icmp import ( "net" "strconv" "syscall" ) func sockaddr(family int, address string) (syscall.Sockaddr, error) { switch family { case syscall.AF_INET: a, err := net.ResolveIPAddr("ip4", address) if err != nil { return nil, err } if len(a.IP) == 0 { a.IP = net.IPv4zero } if a.IP = a.IP.To4(); a.IP == nil { return nil, net.InvalidAddrError("non-ipv4 address") } sa := &syscall.SockaddrInet4{} copy(sa.Addr[:], a.IP) return sa, nil case syscall.AF_INET6: a, err := net.ResolveIPAddr("ip6", address) if err != nil { return nil, err } if len(a.IP) == 0 { a.IP = net.IPv6unspecified } if a.IP.Equal(net.IPv4zero) { a.IP = net.IPv6unspecified } if a.IP = a.IP.To16(); a.IP == nil || a.IP.To4() != nil { return nil, net.InvalidAddrError("non-ipv6 address") } sa := &syscall.SockaddrInet6{ZoneId: zoneToUint32(a.Zone)} copy(sa.Addr[:], a.IP) return sa, nil default: return nil, net.InvalidAddrError("unexpected family") } } func zoneToUint32(zone string) uint32 { if zone == "" { return 0 } if ifi, err := net.InterfaceByName(zone); err == nil { return uint32(ifi.Index) } n, err := strconv.Atoi(zone) if err != nil { return 0 } return uint32(n) } func last(s string, b byte) int { i := len(s) for i--; i >= 0; i-- { if s[i] == b { break } } return i } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/interface.go000066400000000000000000000131401264464372400236560ustar00rootroot00000000000000// Copyright 2015 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 icmp import ( "net" "strings" "golang.org/x/net/internal/iana" ) const ( classInterfaceInfo = 2 afiIPv4 = 1 afiIPv6 = 2 ) const ( attrMTU = 1 << iota attrName attrIPAddr attrIfIndex ) // An InterfaceInfo represents interface and next-hop identification. type InterfaceInfo struct { Class int // extension object class number Type int // extension object sub-type Interface *net.Interface Addr *net.IPAddr } func (ifi *InterfaceInfo) nameLen() int { if len(ifi.Interface.Name) > 63 { return 64 } l := 1 + len(ifi.Interface.Name) return (l + 3) &^ 3 } func (ifi *InterfaceInfo) attrsAndLen(proto int) (attrs, l int) { l = 4 if ifi.Interface != nil && ifi.Interface.Index > 0 { attrs |= attrIfIndex l += 4 if len(ifi.Interface.Name) > 0 { attrs |= attrName l += ifi.nameLen() } if ifi.Interface.MTU > 0 { attrs |= attrMTU l += 4 } } if ifi.Addr != nil { switch proto { case iana.ProtocolICMP: if ifi.Addr.IP.To4() != nil { attrs |= attrIPAddr l += 4 + net.IPv4len } case iana.ProtocolIPv6ICMP: if ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil { attrs |= attrIPAddr l += 4 + net.IPv6len } } } return } // Len implements the Len method of Extension interface. func (ifi *InterfaceInfo) Len(proto int) int { _, l := ifi.attrsAndLen(proto) return l } // Marshal implements the Marshal method of Extension interface. func (ifi *InterfaceInfo) Marshal(proto int) ([]byte, error) { attrs, l := ifi.attrsAndLen(proto) b := make([]byte, l) if err := ifi.marshal(proto, b, attrs, l); err != nil { return nil, err } return b, nil } func (ifi *InterfaceInfo) marshal(proto int, b []byte, attrs, l int) error { b[0], b[1] = byte(l>>8), byte(l) b[2], b[3] = classInterfaceInfo, byte(ifi.Type) for b = b[4:]; len(b) > 0 && attrs != 0; { switch { case attrs&attrIfIndex != 0: b = ifi.marshalIfIndex(proto, b) attrs &^= attrIfIndex case attrs&attrIPAddr != 0: b = ifi.marshalIPAddr(proto, b) attrs &^= attrIPAddr case attrs&attrName != 0: b = ifi.marshalName(proto, b) attrs &^= attrName case attrs&attrMTU != 0: b = ifi.marshalMTU(proto, b) attrs &^= attrMTU } } return nil } func (ifi *InterfaceInfo) marshalIfIndex(proto int, b []byte) []byte { b[0], b[1], b[2], b[3] = byte(ifi.Interface.Index>>24), byte(ifi.Interface.Index>>16), byte(ifi.Interface.Index>>8), byte(ifi.Interface.Index) return b[4:] } func (ifi *InterfaceInfo) parseIfIndex(b []byte) ([]byte, error) { if len(b) < 4 { return nil, errMessageTooShort } ifi.Interface.Index = int(b[0])<<24 | int(b[1])<<16 | int(b[2])<<8 | int(b[3]) return b[4:], nil } func (ifi *InterfaceInfo) marshalIPAddr(proto int, b []byte) []byte { switch proto { case iana.ProtocolICMP: b[0], b[1] = byte(afiIPv4>>8), byte(afiIPv4) copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4()) b = b[4+net.IPv4len:] case iana.ProtocolIPv6ICMP: b[0], b[1] = byte(afiIPv6>>8), byte(afiIPv6) copy(b[4:4+net.IPv6len], ifi.Addr.IP.To16()) b = b[4+net.IPv6len:] } return b } func (ifi *InterfaceInfo) parseIPAddr(b []byte) ([]byte, error) { if len(b) < 4 { return nil, errMessageTooShort } afi := int(b[0])<<8 | int(b[1]) b = b[4:] switch afi { case afiIPv4: if len(b) < net.IPv4len { return nil, errMessageTooShort } ifi.Addr.IP = make(net.IP, net.IPv4len) copy(ifi.Addr.IP, b[:net.IPv4len]) b = b[net.IPv4len:] case afiIPv6: if len(b) < net.IPv6len { return nil, errMessageTooShort } ifi.Addr.IP = make(net.IP, net.IPv6len) copy(ifi.Addr.IP, b[:net.IPv6len]) b = b[net.IPv6len:] } return b, nil } func (ifi *InterfaceInfo) marshalName(proto int, b []byte) []byte { l := byte(ifi.nameLen()) b[0] = l copy(b[1:], []byte(ifi.Interface.Name)) return b[l:] } func (ifi *InterfaceInfo) parseName(b []byte) ([]byte, error) { if 4 > len(b) || len(b) < int(b[0]) { return nil, errMessageTooShort } l := int(b[0]) if l%4 != 0 || 4 > l || l > 64 { return nil, errInvalidExtension } var name [63]byte copy(name[:], b[1:l]) ifi.Interface.Name = strings.Trim(string(name[:]), "\000") return b[l:], nil } func (ifi *InterfaceInfo) marshalMTU(proto int, b []byte) []byte { b[0], b[1], b[2], b[3] = byte(ifi.Interface.MTU>>24), byte(ifi.Interface.MTU>>16), byte(ifi.Interface.MTU>>8), byte(ifi.Interface.MTU) return b[4:] } func (ifi *InterfaceInfo) parseMTU(b []byte) ([]byte, error) { if len(b) < 4 { return nil, errMessageTooShort } ifi.Interface.MTU = int(b[0])<<24 | int(b[1])<<16 | int(b[2])<<8 | int(b[3]) return b[4:], nil } func parseInterfaceInfo(b []byte) (Extension, error) { ifi := &InterfaceInfo{ Class: int(b[2]), Type: int(b[3]), } if ifi.Type&(attrIfIndex|attrName|attrMTU) != 0 { ifi.Interface = &net.Interface{} } if ifi.Type&attrIPAddr != 0 { ifi.Addr = &net.IPAddr{} } attrs := ifi.Type & (attrIfIndex | attrIPAddr | attrName | attrMTU) for b = b[4:]; len(b) > 0 && attrs != 0; { var err error switch { case attrs&attrIfIndex != 0: b, err = ifi.parseIfIndex(b) attrs &^= attrIfIndex case attrs&attrIPAddr != 0: b, err = ifi.parseIPAddr(b) attrs &^= attrIPAddr case attrs&attrName != 0: b, err = ifi.parseName(b) attrs &^= attrName case attrs&attrMTU != 0: b, err = ifi.parseMTU(b) attrs &^= attrMTU } if err != nil { return nil, err } } if ifi.Interface != nil && ifi.Interface.Name != "" && ifi.Addr != nil && ifi.Addr.IP.To16() != nil && ifi.Addr.IP.To4() == nil { ifi.Addr.Zone = ifi.Interface.Name } return ifi, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/ipv4.go000066400000000000000000000032441264464372400226040ustar00rootroot00000000000000// Copyright 2014 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 icmp import ( "net" "runtime" "unsafe" "golang.org/x/net/ipv4" ) // See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html. var freebsdVersion uint32 // ParseIPv4Header parses b as an IPv4 header of ICMP error message // invoking packet, which is contained in ICMP error message. func ParseIPv4Header(b []byte) (*ipv4.Header, error) { if len(b) < ipv4.HeaderLen { return nil, errHeaderTooShort } hdrlen := int(b[0]&0x0f) << 2 if hdrlen > len(b) { return nil, errBufferTooShort } h := &ipv4.Header{ Version: int(b[0] >> 4), Len: hdrlen, TOS: int(b[1]), ID: int(b[4])<<8 | int(b[5]), FragOff: int(b[6])<<8 | int(b[7]), TTL: int(b[8]), Protocol: int(b[9]), Checksum: int(b[10])<<8 | int(b[11]), Src: net.IPv4(b[12], b[13], b[14], b[15]), Dst: net.IPv4(b[16], b[17], b[18], b[19]), } switch runtime.GOOS { case "darwin": // TODO(mikio): fix potential misaligned memory access h.TotalLen = int(*(*uint16)(unsafe.Pointer(&b[2:3][0]))) case "freebsd": if freebsdVersion >= 1000000 { h.TotalLen = int(b[2])<<8 | int(b[3]) } else { // TODO(mikio): fix potential misaligned memory access h.TotalLen = int(*(*uint16)(unsafe.Pointer(&b[2:3][0]))) } default: h.TotalLen = int(b[2])<<8 | int(b[3]) } h.Flags = ipv4.HeaderFlags(h.FragOff&0xe000) >> 13 h.FragOff = h.FragOff & 0x1fff if hdrlen-ipv4.HeaderLen > 0 { h.Options = make([]byte, hdrlen-ipv4.HeaderLen) copy(h.Options, b[ipv4.HeaderLen:]) } return h, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/ipv4_test.go000066400000000000000000000027171264464372400236470ustar00rootroot00000000000000// Copyright 2014 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 icmp import ( "net" "reflect" "runtime" "testing" "golang.org/x/net/ipv4" ) var ( wireHeaderFromKernel = [ipv4.HeaderLen]byte{ 0x45, 0x01, 0xbe, 0xef, 0xca, 0xfe, 0x45, 0xdc, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, } wireHeaderFromTradBSDKernel = [ipv4.HeaderLen]byte{ 0x45, 0x01, 0xef, 0xbe, 0xca, 0xfe, 0x45, 0xdc, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, } // TODO(mikio): Add platform dependent wire header formats when // we support new platforms. testHeader = &ipv4.Header{ Version: ipv4.Version, Len: ipv4.HeaderLen, TOS: 1, TotalLen: 0xbeef, ID: 0xcafe, Flags: ipv4.DontFragment, FragOff: 1500, TTL: 255, Protocol: 1, Checksum: 0xdead, Src: net.IPv4(172, 16, 254, 254), Dst: net.IPv4(192, 168, 0, 1), } ) func TestParseIPv4Header(t *testing.T) { var wh []byte switch runtime.GOOS { case "darwin": wh = wireHeaderFromTradBSDKernel[:] case "freebsd": if freebsdVersion >= 1000000 { wh = wireHeaderFromKernel[:] } else { wh = wireHeaderFromTradBSDKernel[:] } default: wh = wireHeaderFromKernel[:] } h, err := ParseIPv4Header(wh) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(h, testHeader) { t.Fatalf("got %#v; want %#v", h, testHeader) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/ipv6.go000066400000000000000000000010521264464372400226010ustar00rootroot00000000000000// Copyright 2013 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 icmp import ( "net" "golang.org/x/net/internal/iana" ) const ipv6PseudoHeaderLen = 2*net.IPv6len + 8 // IPv6PseudoHeader returns an IPv6 pseudo header for checkusm // calculation. func IPv6PseudoHeader(src, dst net.IP) []byte { b := make([]byte, ipv6PseudoHeaderLen) copy(b, src.To16()) copy(b[net.IPv6len:], dst.To16()) b[len(b)-1] = byte(iana.ProtocolIPv6ICMP) return b } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/listen_posix.go000066400000000000000000000053211264464372400244400ustar00rootroot00000000000000// Copyright 2014 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. // +build darwin dragonfly freebsd linux netbsd openbsd solaris windows package icmp import ( "net" "os" "runtime" "syscall" "golang.org/x/net/internal/iana" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" ) const sysIP_STRIPHDR = 0x17 // for now only darwin supports this option // ListenPacket listens for incoming ICMP packets addressed to // address. See net.Dial for the syntax of address. // // For non-privileged datagram-oriented ICMP endpoints, network must // be "udp4" or "udp6". The endpoint allows to read, write a few // limited ICMP messages such as echo request and echo reply. // Currently only Darwin and Linux support this. // // Examples: // ListenPacket("udp4", "192.168.0.1") // ListenPacket("udp4", "0.0.0.0") // ListenPacket("udp6", "fe80::1%en0") // ListenPacket("udp6", "::") // // For privileged raw ICMP endpoints, network must be "ip4" or "ip6" // followed by a colon and an ICMP protocol number or name. // // Examples: // ListenPacket("ip4:icmp", "192.168.0.1") // ListenPacket("ip4:1", "0.0.0.0") // ListenPacket("ip6:ipv6-icmp", "fe80::1%en0") // ListenPacket("ip6:58", "::") func ListenPacket(network, address string) (*PacketConn, error) { var family, proto int switch network { case "udp4": family, proto = syscall.AF_INET, iana.ProtocolICMP case "udp6": family, proto = syscall.AF_INET6, iana.ProtocolIPv6ICMP default: i := last(network, ':') switch network[:i] { case "ip4": proto = iana.ProtocolICMP case "ip6": proto = iana.ProtocolIPv6ICMP } } var cerr error var c net.PacketConn switch family { case syscall.AF_INET, syscall.AF_INET6: s, err := syscall.Socket(family, syscall.SOCK_DGRAM, proto) if err != nil { return nil, os.NewSyscallError("socket", err) } defer syscall.Close(s) if runtime.GOOS == "darwin" && family == syscall.AF_INET { if err := syscall.SetsockoptInt(s, iana.ProtocolIP, sysIP_STRIPHDR, 1); err != nil { return nil, os.NewSyscallError("setsockopt", err) } } sa, err := sockaddr(family, address) if err != nil { return nil, err } if err := syscall.Bind(s, sa); err != nil { return nil, os.NewSyscallError("bind", err) } f := os.NewFile(uintptr(s), "datagram-oriented icmp") defer f.Close() c, cerr = net.FilePacketConn(f) default: c, cerr = net.ListenPacket(network, address) } if cerr != nil { return nil, cerr } switch proto { case iana.ProtocolICMP: return &PacketConn{c: c, p4: ipv4.NewPacketConn(c)}, nil case iana.ProtocolIPv6ICMP: return &PacketConn{c: c, p6: ipv6.NewPacketConn(c)}, nil default: return &PacketConn{c: c}, nil } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/listen_stub.go000066400000000000000000000021411264464372400242500ustar00rootroot00000000000000// Copyright 2014 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. // +build nacl plan9 package icmp // ListenPacket listens for incoming ICMP packets addressed to // address. See net.Dial for the syntax of address. // // For non-privileged datagram-oriented ICMP endpoints, network must // be "udp4" or "udp6". The endpoint allows to read, write a few // limited ICMP messages such as echo request and echo reply. // Currently only Darwin and Linux support this. // // Examples: // ListenPacket("udp4", "192.168.0.1") // ListenPacket("udp4", "0.0.0.0") // ListenPacket("udp6", "fe80::1%en0") // ListenPacket("udp6", "::") // // For privileged raw ICMP endpoints, network must be "ip4" or "ip6" // followed by a colon and an ICMP protocol number or name. // // Examples: // ListenPacket("ip4:icmp", "192.168.0.1") // ListenPacket("ip4:1", "0.0.0.0") // ListenPacket("ip6:ipv6-icmp", "fe80::1%en0") // ListenPacket("ip6:58", "::") func ListenPacket(network, address string) (*PacketConn, error) { return nil, errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/message.go000066400000000000000000000104171264464372400233460ustar00rootroot00000000000000// Copyright 2012 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 icmp provides basic functions for the manipulation of // messages used in the Internet Control Message Protocols, // ICMPv4 and ICMPv6. // // ICMPv4 and ICMPv6 are defined in RFC 792 and RFC 4443. // Multi-part message support for ICMP is defined in RFC 4884. // ICMP extensions for MPLS are defined in RFC 4950. // ICMP extensions for interface and next-hop identification are // defined in RFC 5837. package icmp // import "golang.org/x/net/icmp" import ( "errors" "net" "syscall" "golang.org/x/net/internal/iana" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" ) var ( errMessageTooShort = errors.New("message too short") errHeaderTooShort = errors.New("header too short") errBufferTooShort = errors.New("buffer too short") errOpNoSupport = errors.New("operation not supported") errNoExtension = errors.New("no extension") errInvalidExtension = errors.New("invalid extension") ) func checksum(b []byte) uint16 { csumcv := len(b) - 1 // checksum coverage s := uint32(0) for i := 0; i < csumcv; i += 2 { s += uint32(b[i+1])<<8 | uint32(b[i]) } if csumcv&1 == 0 { s += uint32(b[csumcv]) } s = s>>16 + s&0xffff s = s + s>>16 return ^uint16(s) } // A Type represents an ICMP message type. type Type interface { Protocol() int } // A Message represents an ICMP message. type Message struct { Type Type // type, either ipv4.ICMPType or ipv6.ICMPType Code int // code Checksum int // checksum Body MessageBody // body } // Marshal returns the binary encoding of the ICMP message m. // // For an ICMPv4 message, the returned message always contains the // calculated checksum field. // // For an ICMPv6 message, the returned message contains the calculated // checksum field when psh is not nil, otherwise the kernel will // compute the checksum field during the message transmission. // When psh is not nil, it must be the pseudo header for IPv6. func (m *Message) Marshal(psh []byte) ([]byte, error) { var mtype int switch typ := m.Type.(type) { case ipv4.ICMPType: mtype = int(typ) case ipv6.ICMPType: mtype = int(typ) default: return nil, syscall.EINVAL } b := []byte{byte(mtype), byte(m.Code), 0, 0} if m.Type.Protocol() == iana.ProtocolIPv6ICMP && psh != nil { b = append(psh, b...) } if m.Body != nil && m.Body.Len(m.Type.Protocol()) != 0 { mb, err := m.Body.Marshal(m.Type.Protocol()) if err != nil { return nil, err } b = append(b, mb...) } if m.Type.Protocol() == iana.ProtocolIPv6ICMP { if psh == nil { // cannot calculate checksum here return b, nil } off, l := 2*net.IPv6len, len(b)-len(psh) b[off], b[off+1], b[off+2], b[off+3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l) } s := checksum(b) // Place checksum back in header; using ^= avoids the // assumption the checksum bytes are zero. b[len(psh)+2] ^= byte(s) b[len(psh)+3] ^= byte(s >> 8) return b[len(psh):], nil } var parseFns = map[Type]func(int, []byte) (MessageBody, error){ ipv4.ICMPTypeDestinationUnreachable: parseDstUnreach, ipv4.ICMPTypeTimeExceeded: parseTimeExceeded, ipv4.ICMPTypeParameterProblem: parseParamProb, ipv4.ICMPTypeEcho: parseEcho, ipv4.ICMPTypeEchoReply: parseEcho, ipv6.ICMPTypeDestinationUnreachable: parseDstUnreach, ipv6.ICMPTypePacketTooBig: parsePacketTooBig, ipv6.ICMPTypeTimeExceeded: parseTimeExceeded, ipv6.ICMPTypeParameterProblem: parseParamProb, ipv6.ICMPTypeEchoRequest: parseEcho, ipv6.ICMPTypeEchoReply: parseEcho, } // ParseMessage parses b as an ICMP message. // Proto must be either the ICMPv4 or ICMPv6 protocol number. func ParseMessage(proto int, b []byte) (*Message, error) { if len(b) < 4 { return nil, errMessageTooShort } var err error m := &Message{Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])} switch proto { case iana.ProtocolICMP: m.Type = ipv4.ICMPType(b[0]) case iana.ProtocolIPv6ICMP: m.Type = ipv6.ICMPType(b[0]) default: return nil, syscall.EINVAL } if fn, ok := parseFns[m.Type]; !ok { m.Body, err = parseDefaultMessageBody(proto, b[4:]) } else { m.Body, err = fn(proto, b[4:]) } if err != nil { return nil, err } return m, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/message_test.go000066400000000000000000000057041264464372400244100ustar00rootroot00000000000000// Copyright 2014 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 icmp_test import ( "net" "reflect" "testing" "golang.org/x/net/icmp" "golang.org/x/net/internal/iana" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" ) var marshalAndParseMessageForIPv4Tests = []icmp.Message{ { Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15, Body: &icmp.DstUnreach{ Data: []byte("ERROR-INVOKING-PACKET"), }, }, { Type: ipv4.ICMPTypeTimeExceeded, Code: 1, Body: &icmp.TimeExceeded{ Data: []byte("ERROR-INVOKING-PACKET"), }, }, { Type: ipv4.ICMPTypeParameterProblem, Code: 2, Body: &icmp.ParamProb{ Pointer: 8, Data: []byte("ERROR-INVOKING-PACKET"), }, }, { Type: ipv4.ICMPTypeEcho, Code: 0, Body: &icmp.Echo{ ID: 1, Seq: 2, Data: []byte("HELLO-R-U-THERE"), }, }, { Type: ipv4.ICMPTypePhoturis, Body: &icmp.DefaultMessageBody{ Data: []byte{0x80, 0x40, 0x20, 0x10}, }, }, } func TestMarshalAndParseMessageForIPv4(t *testing.T) { for i, tt := range marshalAndParseMessageForIPv4Tests { b, err := tt.Marshal(nil) if err != nil { t.Fatal(err) } m, err := icmp.ParseMessage(iana.ProtocolICMP, b) if err != nil { t.Fatal(err) } if m.Type != tt.Type || m.Code != tt.Code { t.Errorf("#%v: got %v; want %v", i, m, &tt) } if !reflect.DeepEqual(m.Body, tt.Body) { t.Errorf("#%v: got %v; want %v", i, m.Body, tt.Body) } } } var marshalAndParseMessageForIPv6Tests = []icmp.Message{ { Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6, Body: &icmp.DstUnreach{ Data: []byte("ERROR-INVOKING-PACKET"), }, }, { Type: ipv6.ICMPTypePacketTooBig, Code: 0, Body: &icmp.PacketTooBig{ MTU: 1<<16 - 1, Data: []byte("ERROR-INVOKING-PACKET"), }, }, { Type: ipv6.ICMPTypeTimeExceeded, Code: 1, Body: &icmp.TimeExceeded{ Data: []byte("ERROR-INVOKING-PACKET"), }, }, { Type: ipv6.ICMPTypeParameterProblem, Code: 2, Body: &icmp.ParamProb{ Pointer: 8, Data: []byte("ERROR-INVOKING-PACKET"), }, }, { Type: ipv6.ICMPTypeEchoRequest, Code: 0, Body: &icmp.Echo{ ID: 1, Seq: 2, Data: []byte("HELLO-R-U-THERE"), }, }, { Type: ipv6.ICMPTypeDuplicateAddressConfirmation, Body: &icmp.DefaultMessageBody{ Data: []byte{0x80, 0x40, 0x20, 0x10}, }, }, } func TestMarshalAndParseMessageForIPv6(t *testing.T) { pshicmp := icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1")) for i, tt := range marshalAndParseMessageForIPv6Tests { for _, psh := range [][]byte{pshicmp, nil} { b, err := tt.Marshal(psh) if err != nil { t.Fatal(err) } m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, b) if err != nil { t.Fatal(err) } if m.Type != tt.Type || m.Code != tt.Code { t.Errorf("#%v: got %v; want %v", i, m, &tt) } if !reflect.DeepEqual(m.Body, tt.Body) { t.Errorf("#%v: got %v; want %v", i, m.Body, tt.Body) } } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/messagebody.go000066400000000000000000000022701264464372400242220ustar00rootroot00000000000000// Copyright 2012 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 icmp // A MessageBody represents an ICMP message body. type MessageBody interface { // Len returns the length of ICMP message body. // Proto must be either the ICMPv4 or ICMPv6 protocol number. Len(proto int) int // Marshal returns the binary encoding of ICMP message body. // Proto must be either the ICMPv4 or ICMPv6 protocol number. Marshal(proto int) ([]byte, error) } // A DefaultMessageBody represents the default message body. type DefaultMessageBody struct { Data []byte // data } // Len implements the Len method of MessageBody interface. func (p *DefaultMessageBody) Len(proto int) int { if p == nil { return 0 } return len(p.Data) } // Marshal implements the Marshal method of MessageBody interface. func (p *DefaultMessageBody) Marshal(proto int) ([]byte, error) { return p.Data, nil } // parseDefaultMessageBody parses b as an ICMP message body. func parseDefaultMessageBody(proto int, b []byte) (MessageBody, error) { p := &DefaultMessageBody{Data: make([]byte, len(b))} copy(p.Data, b) return p, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/mpls.go000066400000000000000000000035341264464372400226770ustar00rootroot00000000000000// Copyright 2015 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 icmp // A MPLSLabel represents a MPLS label stack entry. type MPLSLabel struct { Label int // label value TC int // traffic class; formerly experimental use S bool // bottom of stack TTL int // time to live } const ( classMPLSLabelStack = 1 typeIncomingMPLSLabelStack = 1 ) // A MPLSLabelStack represents a MPLS label stack. type MPLSLabelStack struct { Class int // extension object class number Type int // extension object sub-type Labels []MPLSLabel } // Len implements the Len method of Extension interface. func (ls *MPLSLabelStack) Len(proto int) int { return 4 + (4 * len(ls.Labels)) } // Marshal implements the Marshal method of Extension interface. func (ls *MPLSLabelStack) Marshal(proto int) ([]byte, error) { b := make([]byte, ls.Len(proto)) if err := ls.marshal(proto, b); err != nil { return nil, err } return b, nil } func (ls *MPLSLabelStack) marshal(proto int, b []byte) error { l := ls.Len(proto) b[0], b[1] = byte(l>>8), byte(l) b[2], b[3] = classMPLSLabelStack, typeIncomingMPLSLabelStack off := 4 for _, ll := range ls.Labels { b[off], b[off+1], b[off+2] = byte(ll.Label>>12), byte(ll.Label>>4&0xff), byte(ll.Label<<4&0xf0) b[off+2] |= byte(ll.TC << 1 & 0x0e) if ll.S { b[off+2] |= 0x1 } b[off+3] = byte(ll.TTL) off += 4 } return nil } func parseMPLSLabelStack(b []byte) (Extension, error) { ls := &MPLSLabelStack{ Class: int(b[2]), Type: int(b[3]), } for b = b[4:]; len(b) >= 4; b = b[4:] { ll := MPLSLabel{ Label: int(b[0])<<12 | int(b[1])<<4 | int(b[2])>>4, TC: int(b[2]&0x0e) >> 1, TTL: int(b[3]), } if b[2]&0x1 != 0 { ll.S = true } ls.Labels = append(ls.Labels, ll) } return ls, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/multipart.go000066400000000000000000000057721264464372400237530ustar00rootroot00000000000000// Copyright 2015 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 icmp import "golang.org/x/net/internal/iana" // multipartMessageBodyDataLen takes b as an original datagram and // exts as extensions, and returns a required length for message body // and a required length for a padded original datagram in wire // format. func multipartMessageBodyDataLen(proto int, b []byte, exts []Extension) (bodyLen, dataLen int) { for _, ext := range exts { bodyLen += ext.Len(proto) } if bodyLen > 0 { dataLen = multipartMessageOrigDatagramLen(proto, b) bodyLen += 4 // length of extension header } else { dataLen = len(b) } bodyLen += dataLen return bodyLen, dataLen } // multipartMessageOrigDatagramLen takes b as an original datagram, // and returns a required length for a padded orignal datagram in wire // format. func multipartMessageOrigDatagramLen(proto int, b []byte) int { roundup := func(b []byte, align int) int { // According to RFC 4884, the padded original datagram // field must contain at least 128 octets. if len(b) < 128 { return 128 } r := len(b) return (r + align - 1) & ^(align - 1) } switch proto { case iana.ProtocolICMP: return roundup(b, 4) case iana.ProtocolIPv6ICMP: return roundup(b, 8) default: return len(b) } } // marshalMultipartMessageBody takes data as an original datagram and // exts as extesnsions, and returns a binary encoding of message body. // It can be used for non-multipart message bodies when exts is nil. func marshalMultipartMessageBody(proto int, data []byte, exts []Extension) ([]byte, error) { bodyLen, dataLen := multipartMessageBodyDataLen(proto, data, exts) b := make([]byte, 4+bodyLen) copy(b[4:], data) off := dataLen + 4 if len(exts) > 0 { b[dataLen+4] = byte(extensionVersion << 4) off += 4 // length of object header for _, ext := range exts { switch ext := ext.(type) { case *MPLSLabelStack: if err := ext.marshal(proto, b[off:]); err != nil { return nil, err } off += ext.Len(proto) case *InterfaceInfo: attrs, l := ext.attrsAndLen(proto) if err := ext.marshal(proto, b[off:], attrs, l); err != nil { return nil, err } off += ext.Len(proto) } } s := checksum(b[dataLen+4:]) b[dataLen+4+2] ^= byte(s) b[dataLen+4+3] ^= byte(s >> 8) switch proto { case iana.ProtocolICMP: b[1] = byte(dataLen / 4) case iana.ProtocolIPv6ICMP: b[0] = byte(dataLen / 8) } } return b, nil } // parseMultipartMessageBody parses b as either a non-multipart // message body or a multipart message body. func parseMultipartMessageBody(proto int, b []byte) ([]byte, []Extension, error) { var l int switch proto { case iana.ProtocolICMP: l = 4 * int(b[1]) case iana.ProtocolIPv6ICMP: l = 8 * int(b[0]) } if len(b) == 4 { return nil, nil, nil } exts, l, err := parseExtensions(b[4:], l) if err != nil { l = len(b) - 4 } data := make([]byte, l) copy(data, b[4:]) return data, exts, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/multipart_test.go000066400000000000000000000242371264464372400250070ustar00rootroot00000000000000// Copyright 2015 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 icmp_test import ( "fmt" "net" "reflect" "testing" "golang.org/x/net/icmp" "golang.org/x/net/internal/iana" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" ) var marshalAndParseMultipartMessageForIPv4Tests = []icmp.Message{ { Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15, Body: &icmp.DstUnreach{ Data: []byte("ERROR-INVOKING-PACKET"), Extensions: []icmp.Extension{ &icmp.MPLSLabelStack{ Class: 1, Type: 1, Labels: []icmp.MPLSLabel{ { Label: 16014, TC: 0x4, S: true, TTL: 255, }, }, }, &icmp.InterfaceInfo{ Class: 2, Type: 0x0f, Interface: &net.Interface{ Index: 15, Name: "en101", MTU: 8192, }, Addr: &net.IPAddr{ IP: net.IPv4(192, 168, 0, 1).To4(), }, }, }, }, }, { Type: ipv4.ICMPTypeTimeExceeded, Code: 1, Body: &icmp.TimeExceeded{ Data: []byte("ERROR-INVOKING-PACKET"), Extensions: []icmp.Extension{ &icmp.InterfaceInfo{ Class: 2, Type: 0x0f, Interface: &net.Interface{ Index: 15, Name: "en101", MTU: 8192, }, Addr: &net.IPAddr{ IP: net.IPv4(192, 168, 0, 1).To4(), }, }, &icmp.MPLSLabelStack{ Class: 1, Type: 1, Labels: []icmp.MPLSLabel{ { Label: 16014, TC: 0x4, S: true, TTL: 255, }, }, }, }, }, }, { Type: ipv4.ICMPTypeParameterProblem, Code: 2, Body: &icmp.ParamProb{ Pointer: 8, Data: []byte("ERROR-INVOKING-PACKET"), Extensions: []icmp.Extension{ &icmp.MPLSLabelStack{ Class: 1, Type: 1, Labels: []icmp.MPLSLabel{ { Label: 16014, TC: 0x4, S: true, TTL: 255, }, }, }, &icmp.InterfaceInfo{ Class: 2, Type: 0x0f, Interface: &net.Interface{ Index: 15, Name: "en101", MTU: 8192, }, Addr: &net.IPAddr{ IP: net.IPv4(192, 168, 0, 1).To4(), }, }, &icmp.InterfaceInfo{ Class: 2, Type: 0x2f, Interface: &net.Interface{ Index: 16, Name: "en102", MTU: 8192, }, Addr: &net.IPAddr{ IP: net.IPv4(192, 168, 0, 2).To4(), }, }, }, }, }, } func TestMarshalAndParseMultipartMessageForIPv4(t *testing.T) { for i, tt := range marshalAndParseMultipartMessageForIPv4Tests { b, err := tt.Marshal(nil) if err != nil { t.Fatal(err) } if b[5] != 32 { t.Errorf("#%v: got %v; want 32", i, b[5]) } m, err := icmp.ParseMessage(iana.ProtocolICMP, b) if err != nil { t.Fatal(err) } if m.Type != tt.Type || m.Code != tt.Code { t.Errorf("#%v: got %v; want %v", i, m, &tt) } switch m.Type { case ipv4.ICMPTypeDestinationUnreachable: got, want := m.Body.(*icmp.DstUnreach), tt.Body.(*icmp.DstUnreach) if !reflect.DeepEqual(got.Extensions, want.Extensions) { t.Error(dumpExtensions(i, got.Extensions, want.Extensions)) } if len(got.Data) != 128 { t.Errorf("#%v: got %v; want 128", i, len(got.Data)) } case ipv4.ICMPTypeTimeExceeded: got, want := m.Body.(*icmp.TimeExceeded), tt.Body.(*icmp.TimeExceeded) if !reflect.DeepEqual(got.Extensions, want.Extensions) { t.Error(dumpExtensions(i, got.Extensions, want.Extensions)) } if len(got.Data) != 128 { t.Errorf("#%v: got %v; want 128", i, len(got.Data)) } case ipv4.ICMPTypeParameterProblem: got, want := m.Body.(*icmp.ParamProb), tt.Body.(*icmp.ParamProb) if !reflect.DeepEqual(got.Extensions, want.Extensions) { t.Error(dumpExtensions(i, got.Extensions, want.Extensions)) } if len(got.Data) != 128 { t.Errorf("#%v: got %v; want 128", i, len(got.Data)) } } } } var marshalAndParseMultipartMessageForIPv6Tests = []icmp.Message{ { Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6, Body: &icmp.DstUnreach{ Data: []byte("ERROR-INVOKING-PACKET"), Extensions: []icmp.Extension{ &icmp.MPLSLabelStack{ Class: 1, Type: 1, Labels: []icmp.MPLSLabel{ { Label: 16014, TC: 0x4, S: true, TTL: 255, }, }, }, &icmp.InterfaceInfo{ Class: 2, Type: 0x0f, Interface: &net.Interface{ Index: 15, Name: "en101", MTU: 8192, }, Addr: &net.IPAddr{ IP: net.ParseIP("fe80::1"), Zone: "en101", }, }, }, }, }, { Type: ipv6.ICMPTypeTimeExceeded, Code: 1, Body: &icmp.TimeExceeded{ Data: []byte("ERROR-INVOKING-PACKET"), Extensions: []icmp.Extension{ &icmp.InterfaceInfo{ Class: 2, Type: 0x0f, Interface: &net.Interface{ Index: 15, Name: "en101", MTU: 8192, }, Addr: &net.IPAddr{ IP: net.ParseIP("fe80::1"), Zone: "en101", }, }, &icmp.MPLSLabelStack{ Class: 1, Type: 1, Labels: []icmp.MPLSLabel{ { Label: 16014, TC: 0x4, S: true, TTL: 255, }, }, }, &icmp.InterfaceInfo{ Class: 2, Type: 0x2f, Interface: &net.Interface{ Index: 16, Name: "en102", MTU: 8192, }, Addr: &net.IPAddr{ IP: net.ParseIP("fe80::1"), Zone: "en102", }, }, }, }, }, } func TestMarshalAndParseMultipartMessageForIPv6(t *testing.T) { pshicmp := icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1")) for i, tt := range marshalAndParseMultipartMessageForIPv6Tests { for _, psh := range [][]byte{pshicmp, nil} { b, err := tt.Marshal(psh) if err != nil { t.Fatal(err) } if b[4] != 16 { t.Errorf("#%v: got %v; want 16", i, b[4]) } m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, b) if err != nil { t.Fatal(err) } if m.Type != tt.Type || m.Code != tt.Code { t.Errorf("#%v: got %v; want %v", i, m, &tt) } switch m.Type { case ipv6.ICMPTypeDestinationUnreachable: got, want := m.Body.(*icmp.DstUnreach), tt.Body.(*icmp.DstUnreach) if !reflect.DeepEqual(got.Extensions, want.Extensions) { t.Error(dumpExtensions(i, got.Extensions, want.Extensions)) } if len(got.Data) != 128 { t.Errorf("#%v: got %v; want 128", i, len(got.Data)) } case ipv6.ICMPTypeTimeExceeded: got, want := m.Body.(*icmp.TimeExceeded), tt.Body.(*icmp.TimeExceeded) if !reflect.DeepEqual(got.Extensions, want.Extensions) { t.Error(dumpExtensions(i, got.Extensions, want.Extensions)) } if len(got.Data) != 128 { t.Errorf("#%v: got %v; want 128", i, len(got.Data)) } } } } } func dumpExtensions(i int, gotExts, wantExts []icmp.Extension) string { var s string for j, got := range gotExts { switch got := got.(type) { case *icmp.MPLSLabelStack: want := wantExts[j].(*icmp.MPLSLabelStack) if !reflect.DeepEqual(got, want) { s += fmt.Sprintf("#%v/%v: got %#v; want %#v\n", i, j, got, want) } case *icmp.InterfaceInfo: want := wantExts[j].(*icmp.InterfaceInfo) if !reflect.DeepEqual(got, want) { s += fmt.Sprintf("#%v/%v: got %#v, %#v, %#v; want %#v, %#v, %#v\n", i, j, got, got.Interface, got.Addr, want, want.Interface, want.Addr) } } } return s[:len(s)-1] } var multipartMessageBodyLenTests = []struct { proto int in icmp.MessageBody out int }{ { iana.ProtocolICMP, &icmp.DstUnreach{ Data: make([]byte, ipv4.HeaderLen), }, 4 + ipv4.HeaderLen, // unused and original datagram }, { iana.ProtocolICMP, &icmp.TimeExceeded{ Data: make([]byte, ipv4.HeaderLen), }, 4 + ipv4.HeaderLen, // unused and original datagram }, { iana.ProtocolICMP, &icmp.ParamProb{ Data: make([]byte, ipv4.HeaderLen), }, 4 + ipv4.HeaderLen, // [pointer, unused] and original datagram }, { iana.ProtocolICMP, &icmp.ParamProb{ Data: make([]byte, ipv4.HeaderLen), Extensions: []icmp.Extension{ &icmp.MPLSLabelStack{}, }, }, 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram }, { iana.ProtocolICMP, &icmp.ParamProb{ Data: make([]byte, 128), Extensions: []icmp.Extension{ &icmp.MPLSLabelStack{}, }, }, 4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram }, { iana.ProtocolICMP, &icmp.ParamProb{ Data: make([]byte, 129), Extensions: []icmp.Extension{ &icmp.MPLSLabelStack{}, }, }, 4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram }, { iana.ProtocolIPv6ICMP, &icmp.DstUnreach{ Data: make([]byte, ipv6.HeaderLen), }, 4 + ipv6.HeaderLen, // unused and original datagram }, { iana.ProtocolIPv6ICMP, &icmp.PacketTooBig{ Data: make([]byte, ipv6.HeaderLen), }, 4 + ipv6.HeaderLen, // mtu and original datagram }, { iana.ProtocolIPv6ICMP, &icmp.TimeExceeded{ Data: make([]byte, ipv6.HeaderLen), }, 4 + ipv6.HeaderLen, // unused and original datagram }, { iana.ProtocolIPv6ICMP, &icmp.ParamProb{ Data: make([]byte, ipv6.HeaderLen), }, 4 + ipv6.HeaderLen, // pointer and original datagram }, { iana.ProtocolIPv6ICMP, &icmp.DstUnreach{ Data: make([]byte, 127), Extensions: []icmp.Extension{ &icmp.MPLSLabelStack{}, }, }, 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram }, { iana.ProtocolIPv6ICMP, &icmp.DstUnreach{ Data: make([]byte, 128), Extensions: []icmp.Extension{ &icmp.MPLSLabelStack{}, }, }, 4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram }, { iana.ProtocolIPv6ICMP, &icmp.DstUnreach{ Data: make([]byte, 129), Extensions: []icmp.Extension{ &icmp.MPLSLabelStack{}, }, }, 4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram }, } func TestMultipartMessageBodyLen(t *testing.T) { for i, tt := range multipartMessageBodyLenTests { if out := tt.in.Len(tt.proto); out != tt.out { t.Errorf("#%d: got %d; want %d", i, out, tt.out) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/packettoobig.go000066400000000000000000000023061264464372400243730ustar00rootroot00000000000000// Copyright 2014 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 icmp // A PacketTooBig represents an ICMP packet too big message body. type PacketTooBig struct { MTU int // maximum transmission unit of the nexthop link Data []byte // data, known as original datagram field } // Len implements the Len method of MessageBody interface. func (p *PacketTooBig) Len(proto int) int { if p == nil { return 0 } return 4 + len(p.Data) } // Marshal implements the Marshal method of MessageBody interface. func (p *PacketTooBig) Marshal(proto int) ([]byte, error) { b := make([]byte, 4+len(p.Data)) b[0], b[1], b[2], b[3] = byte(p.MTU>>24), byte(p.MTU>>16), byte(p.MTU>>8), byte(p.MTU) copy(b[4:], p.Data) return b, nil } // parsePacketTooBig parses b as an ICMP packet too big message body. func parsePacketTooBig(proto int, b []byte) (MessageBody, error) { bodyLen := len(b) if bodyLen < 4 { return nil, errMessageTooShort } p := &PacketTooBig{MTU: int(b[0])<<24 | int(b[1])<<16 | int(b[2])<<8 | int(b[3])} if bodyLen > 4 { p.Data = make([]byte, bodyLen-4) copy(p.Data, b[4:]) } return p, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/paramprob.go000066400000000000000000000033371264464372400237100ustar00rootroot00000000000000// Copyright 2014 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 icmp import "golang.org/x/net/internal/iana" // A ParamProb represents an ICMP parameter problem message body. type ParamProb struct { Pointer uintptr // offset within the data where the error was detected Data []byte // data, known as original datagram field Extensions []Extension // extensions } // Len implements the Len method of MessageBody interface. func (p *ParamProb) Len(proto int) int { if p == nil { return 0 } l, _ := multipartMessageBodyDataLen(proto, p.Data, p.Extensions) return 4 + l } // Marshal implements the Marshal method of MessageBody interface. func (p *ParamProb) Marshal(proto int) ([]byte, error) { if proto == iana.ProtocolIPv6ICMP { b := make([]byte, p.Len(proto)) b[0], b[1], b[2], b[3] = byte(p.Pointer>>24), byte(p.Pointer>>16), byte(p.Pointer>>8), byte(p.Pointer) copy(b[4:], p.Data) return b, nil } b, err := marshalMultipartMessageBody(proto, p.Data, p.Extensions) if err != nil { return nil, err } b[0] = byte(p.Pointer) return b, nil } // parseParamProb parses b as an ICMP parameter problem message body. func parseParamProb(proto int, b []byte) (MessageBody, error) { if len(b) < 4 { return nil, errMessageTooShort } p := &ParamProb{} if proto == iana.ProtocolIPv6ICMP { p.Pointer = uintptr(b[0])<<24 | uintptr(b[1])<<16 | uintptr(b[2])<<8 | uintptr(b[3]) p.Data = make([]byte, len(b)-4) copy(p.Data, b[4:]) return p, nil } p.Pointer = uintptr(b[0]) var err error p.Data, p.Extensions, err = parseMultipartMessageBody(proto, b) if err != nil { return nil, err } return p, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/ping_test.go000066400000000000000000000071161264464372400237200ustar00rootroot00000000000000// Copyright 2014 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 icmp_test import ( "errors" "fmt" "net" "os" "runtime" "testing" "time" "golang.org/x/net/icmp" "golang.org/x/net/internal/iana" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" ) func googleAddr(c *icmp.PacketConn, protocol int) (net.Addr, error) { const host = "www.google.com" ips, err := net.LookupIP(host) if err != nil { return nil, err } netaddr := func(ip net.IP) (net.Addr, error) { switch c.LocalAddr().(type) { case *net.UDPAddr: return &net.UDPAddr{IP: ip}, nil case *net.IPAddr: return &net.IPAddr{IP: ip}, nil default: return nil, errors.New("neither UDPAddr nor IPAddr") } } for _, ip := range ips { switch protocol { case iana.ProtocolICMP: if ip.To4() != nil { return netaddr(ip) } case iana.ProtocolIPv6ICMP: if ip.To16() != nil && ip.To4() == nil { return netaddr(ip) } } } return nil, errors.New("no A or AAAA record") } type pingTest struct { network, address string protocol int mtype icmp.Type } var nonPrivilegedPingTests = []pingTest{ {"udp4", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho}, {"udp6", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest}, } func TestNonPrivilegedPing(t *testing.T) { if testing.Short() { t.Skip("avoid external network") } switch runtime.GOOS { case "darwin": case "linux": t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state") default: t.Skipf("not supported on %s", runtime.GOOS) } for i, tt := range nonPrivilegedPingTests { if err := doPing(tt, i); err != nil { t.Error(err) } } } var privilegedPingTests = []pingTest{ {"ip4:icmp", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho}, {"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest}, } func TestPrivilegedPing(t *testing.T) { if testing.Short() { t.Skip("avoid external network") } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } for i, tt := range privilegedPingTests { if err := doPing(tt, i); err != nil { t.Error(err) } } } func doPing(tt pingTest, seq int) error { c, err := icmp.ListenPacket(tt.network, tt.address) if err != nil { return err } defer c.Close() dst, err := googleAddr(c, tt.protocol) if err != nil { return err } if tt.network != "udp6" && tt.protocol == iana.ProtocolIPv6ICMP { var f ipv6.ICMPFilter f.SetAll(true) f.Accept(ipv6.ICMPTypeDestinationUnreachable) f.Accept(ipv6.ICMPTypePacketTooBig) f.Accept(ipv6.ICMPTypeTimeExceeded) f.Accept(ipv6.ICMPTypeParameterProblem) f.Accept(ipv6.ICMPTypeEchoReply) if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil { return err } } wm := icmp.Message{ Type: tt.mtype, Code: 0, Body: &icmp.Echo{ ID: os.Getpid() & 0xffff, Seq: 1 << uint(seq), Data: []byte("HELLO-R-U-THERE"), }, } wb, err := wm.Marshal(nil) if err != nil { return err } if n, err := c.WriteTo(wb, dst); err != nil { return err } else if n != len(wb) { return fmt.Errorf("got %v; want %v", n, len(wb)) } rb := make([]byte, 1500) if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil { return err } n, peer, err := c.ReadFrom(rb) if err != nil { return err } rm, err := icmp.ParseMessage(tt.protocol, rb[:n]) if err != nil { return err } switch rm.Type { case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply: return nil default: return fmt.Errorf("got %+v from %v; want echo reply", rm, peer) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/sys_freebsd.go000066400000000000000000000004141264464372400242260ustar00rootroot00000000000000// Copyright 2014 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 icmp import "syscall" func init() { freebsdVersion, _ = syscall.SysctlUint32("kern.osreldate") } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/icmp/timeexceeded.go000066400000000000000000000021511264464372400243430ustar00rootroot00000000000000// Copyright 2014 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 icmp // A TimeExceeded represents an ICMP time exceeded message body. type TimeExceeded struct { Data []byte // data, known as original datagram field Extensions []Extension // extensions } // Len implements the Len method of MessageBody interface. func (p *TimeExceeded) Len(proto int) int { if p == nil { return 0 } l, _ := multipartMessageBodyDataLen(proto, p.Data, p.Extensions) return 4 + l } // Marshal implements the Marshal method of MessageBody interface. func (p *TimeExceeded) Marshal(proto int) ([]byte, error) { return marshalMultipartMessageBody(proto, p.Data, p.Extensions) } // parseTimeExceeded parses b as an ICMP time exceeded message body. func parseTimeExceeded(proto int, b []byte) (MessageBody, error) { if len(b) < 4 { return nil, errMessageTooShort } p := &TimeExceeded{} var err error p.Data, p.Extensions, err = parseMultipartMessageBody(proto, b) if err != nil { return nil, err } return p, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/idna/000077500000000000000000000000001264464372400213535ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/idna/idna.go000066400000000000000000000034201264464372400226140ustar00rootroot00000000000000// Copyright 2012 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 idna implements IDNA2008 (Internationalized Domain Names for // Applications), defined in RFC 5890, RFC 5891, RFC 5892, RFC 5893 and // RFC 5894. package idna // import "golang.org/x/net/idna" import ( "strings" "unicode/utf8" ) // TODO(nigeltao): specify when errors occur. For example, is ToASCII(".") or // ToASCII("foo\x00") an error? See also http://www.unicode.org/faq/idn.html#11 // acePrefix is the ASCII Compatible Encoding prefix. const acePrefix = "xn--" // ToASCII converts a domain or domain label to its ASCII form. For example, // ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and // ToASCII("golang") is "golang". func ToASCII(s string) (string, error) { if ascii(s) { return s, nil } labels := strings.Split(s, ".") for i, label := range labels { if !ascii(label) { a, err := encode(acePrefix, label) if err != nil { return "", err } labels[i] = a } } return strings.Join(labels, "."), nil } // ToUnicode converts a domain or domain label to its Unicode form. For example, // ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and // ToUnicode("golang") is "golang". func ToUnicode(s string) (string, error) { if !strings.Contains(s, acePrefix) { return s, nil } labels := strings.Split(s, ".") for i, label := range labels { if strings.HasPrefix(label, acePrefix) { u, err := decode(label[len(acePrefix):]) if err != nil { return "", err } labels[i] = u } } return strings.Join(labels, "."), nil } func ascii(s string) bool { for i := 0; i < len(s); i++ { if s[i] >= utf8.RuneSelf { return false } } return true } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/idna/idna_test.go000066400000000000000000000021151264464372400236530ustar00rootroot00000000000000// Copyright 2012 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 idna import ( "testing" ) var idnaTestCases = [...]struct { ascii, unicode string }{ // Labels. {"books", "books"}, {"xn--bcher-kva", "bücher"}, // Domains. {"foo--xn--bar.org", "foo--xn--bar.org"}, {"golang.org", "golang.org"}, {"example.xn--p1ai", "example.рф"}, {"xn--czrw28b.tw", "商業.tw"}, {"www.xn--mller-kva.de", "www.müller.de"}, } func TestIDNA(t *testing.T) { for _, tc := range idnaTestCases { if a, err := ToASCII(tc.unicode); err != nil { t.Errorf("ToASCII(%q): %v", tc.unicode, err) } else if a != tc.ascii { t.Errorf("ToASCII(%q): got %q, want %q", tc.unicode, a, tc.ascii) } if u, err := ToUnicode(tc.ascii); err != nil { t.Errorf("ToUnicode(%q): %v", tc.ascii, err) } else if u != tc.unicode { t.Errorf("ToUnicode(%q): got %q, want %q", tc.ascii, u, tc.unicode) } } } // TODO(nigeltao): test errors, once we've specified when ToASCII and ToUnicode // return errors. golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/idna/punycode.go000066400000000000000000000105371264464372400235360ustar00rootroot00000000000000// Copyright 2012 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 idna // This file implements the Punycode algorithm from RFC 3492. import ( "fmt" "math" "strings" "unicode/utf8" ) // These parameter values are specified in section 5. // // All computation is done with int32s, so that overflow behavior is identical // regardless of whether int is 32-bit or 64-bit. const ( base int32 = 36 damp int32 = 700 initialBias int32 = 72 initialN int32 = 128 skew int32 = 38 tmax int32 = 26 tmin int32 = 1 ) // decode decodes a string as specified in section 6.2. func decode(encoded string) (string, error) { if encoded == "" { return "", nil } pos := 1 + strings.LastIndex(encoded, "-") if pos == 1 { return "", fmt.Errorf("idna: invalid label %q", encoded) } if pos == len(encoded) { return encoded[:len(encoded)-1], nil } output := make([]rune, 0, len(encoded)) if pos != 0 { for _, r := range encoded[:pos-1] { output = append(output, r) } } i, n, bias := int32(0), initialN, initialBias for pos < len(encoded) { oldI, w := i, int32(1) for k := base; ; k += base { if pos == len(encoded) { return "", fmt.Errorf("idna: invalid label %q", encoded) } digit, ok := decodeDigit(encoded[pos]) if !ok { return "", fmt.Errorf("idna: invalid label %q", encoded) } pos++ i += digit * w if i < 0 { return "", fmt.Errorf("idna: invalid label %q", encoded) } t := k - bias if t < tmin { t = tmin } else if t > tmax { t = tmax } if digit < t { break } w *= base - t if w >= math.MaxInt32/base { return "", fmt.Errorf("idna: invalid label %q", encoded) } } x := int32(len(output) + 1) bias = adapt(i-oldI, x, oldI == 0) n += i / x i %= x if n > utf8.MaxRune || len(output) >= 1024 { return "", fmt.Errorf("idna: invalid label %q", encoded) } output = append(output, 0) copy(output[i+1:], output[i:]) output[i] = n i++ } return string(output), nil } // encode encodes a string as specified in section 6.3 and prepends prefix to // the result. // // The "while h < length(input)" line in the specification becomes "for // remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes. func encode(prefix, s string) (string, error) { output := make([]byte, len(prefix), len(prefix)+1+2*len(s)) copy(output, prefix) delta, n, bias := int32(0), initialN, initialBias b, remaining := int32(0), int32(0) for _, r := range s { if r < 0x80 { b++ output = append(output, byte(r)) } else { remaining++ } } h := b if b > 0 { output = append(output, '-') } for remaining != 0 { m := int32(0x7fffffff) for _, r := range s { if m > r && r >= n { m = r } } delta += (m - n) * (h + 1) if delta < 0 { return "", fmt.Errorf("idna: invalid label %q", s) } n = m for _, r := range s { if r < n { delta++ if delta < 0 { return "", fmt.Errorf("idna: invalid label %q", s) } continue } if r > n { continue } q := delta for k := base; ; k += base { t := k - bias if t < tmin { t = tmin } else if t > tmax { t = tmax } if q < t { break } output = append(output, encodeDigit(t+(q-t)%(base-t))) q = (q - t) / (base - t) } output = append(output, encodeDigit(q)) bias = adapt(delta, h+1, h == b) delta = 0 h++ remaining-- } delta++ n++ } return string(output), nil } func decodeDigit(x byte) (digit int32, ok bool) { switch { case '0' <= x && x <= '9': return int32(x - ('0' - 26)), true case 'A' <= x && x <= 'Z': return int32(x - 'A'), true case 'a' <= x && x <= 'z': return int32(x - 'a'), true } return 0, false } func encodeDigit(digit int32) byte { switch { case 0 <= digit && digit < 26: return byte(digit + 'a') case 26 <= digit && digit < 36: return byte(digit + ('0' - 26)) } panic("idna: internal error in punycode encoding") } // adapt is the bias adaptation function specified in section 6.1. func adapt(delta, numPoints int32, firstTime bool) int32 { if firstTime { delta /= damp } else { delta /= 2 } delta += delta / numPoints k := int32(0) for delta > ((base-tmin)*tmax)/2 { delta /= base - tmin k += base } return k + (base-tmin+1)*delta/(delta+skew) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/idna/punycode_test.go000066400000000000000000000134331264464372400245730ustar00rootroot00000000000000// Copyright 2012 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 idna import ( "strings" "testing" ) var punycodeTestCases = [...]struct { s, encoded string }{ {"", ""}, {"-", "--"}, {"-a", "-a-"}, {"-a-", "-a--"}, {"a", "a-"}, {"a-", "a--"}, {"a-b", "a-b-"}, {"books", "books-"}, {"bücher", "bcher-kva"}, {"Hello世界", "Hello-ck1hg65u"}, {"ü", "tda"}, {"üý", "tdac"}, // The test cases below come from RFC 3492 section 7.1 with Errata 3026. { // (A) Arabic (Egyptian). "\u0644\u064A\u0647\u0645\u0627\u0628\u062A\u0643\u0644" + "\u0645\u0648\u0634\u0639\u0631\u0628\u064A\u061F", "egbpdaj6bu4bxfgehfvwxn", }, { // (B) Chinese (simplified). "\u4ED6\u4EEC\u4E3A\u4EC0\u4E48\u4E0D\u8BF4\u4E2D\u6587", "ihqwcrb4cv8a8dqg056pqjye", }, { // (C) Chinese (traditional). "\u4ED6\u5011\u7232\u4EC0\u9EBD\u4E0D\u8AAA\u4E2D\u6587", "ihqwctvzc91f659drss3x8bo0yb", }, { // (D) Czech. "\u0050\u0072\u006F\u010D\u0070\u0072\u006F\u0073\u0074" + "\u011B\u006E\u0065\u006D\u006C\u0075\u0076\u00ED\u010D" + "\u0065\u0073\u006B\u0079", "Proprostnemluvesky-uyb24dma41a", }, { // (E) Hebrew. "\u05DC\u05DE\u05D4\u05D4\u05DD\u05E4\u05E9\u05D5\u05D8" + "\u05DC\u05D0\u05DE\u05D3\u05D1\u05E8\u05D9\u05DD\u05E2" + "\u05D1\u05E8\u05D9\u05EA", "4dbcagdahymbxekheh6e0a7fei0b", }, { // (F) Hindi (Devanagari). "\u092F\u0939\u0932\u094B\u0917\u0939\u093F\u0928\u094D" + "\u0926\u0940\u0915\u094D\u092F\u094B\u0902\u0928\u0939" + "\u0940\u0902\u092C\u094B\u0932\u0938\u0915\u0924\u0947" + "\u0939\u0948\u0902", "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd", }, { // (G) Japanese (kanji and hiragana). "\u306A\u305C\u307F\u3093\u306A\u65E5\u672C\u8A9E\u3092" + "\u8A71\u3057\u3066\u304F\u308C\u306A\u3044\u306E\u304B", "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa", }, { // (H) Korean (Hangul syllables). "\uC138\uACC4\uC758\uBAA8\uB4E0\uC0AC\uB78C\uB4E4\uC774" + "\uD55C\uAD6D\uC5B4\uB97C\uC774\uD574\uD55C\uB2E4\uBA74" + "\uC5BC\uB9C8\uB098\uC88B\uC744\uAE4C", "989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5j" + "psd879ccm6fea98c", }, { // (I) Russian (Cyrillic). "\u043F\u043E\u0447\u0435\u043C\u0443\u0436\u0435\u043E" + "\u043D\u0438\u043D\u0435\u0433\u043E\u0432\u043E\u0440" + "\u044F\u0442\u043F\u043E\u0440\u0443\u0441\u0441\u043A" + "\u0438", "b1abfaaepdrnnbgefbadotcwatmq2g4l", }, { // (J) Spanish. "\u0050\u006F\u0072\u0071\u0075\u00E9\u006E\u006F\u0070" + "\u0075\u0065\u0064\u0065\u006E\u0073\u0069\u006D\u0070" + "\u006C\u0065\u006D\u0065\u006E\u0074\u0065\u0068\u0061" + "\u0062\u006C\u0061\u0072\u0065\u006E\u0045\u0073\u0070" + "\u0061\u00F1\u006F\u006C", "PorqunopuedensimplementehablarenEspaol-fmd56a", }, { // (K) Vietnamese. "\u0054\u1EA1\u0069\u0073\u0061\u006F\u0068\u1ECD\u006B" + "\u0068\u00F4\u006E\u0067\u0074\u0068\u1EC3\u0063\u0068" + "\u1EC9\u006E\u00F3\u0069\u0074\u0069\u1EBF\u006E\u0067" + "\u0056\u0069\u1EC7\u0074", "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g", }, { // (L) 3B. "\u0033\u5E74\u0042\u7D44\u91D1\u516B\u5148\u751F", "3B-ww4c5e180e575a65lsy2b", }, { // (M) -with-SUPER-MONKEYS. "\u5B89\u5BA4\u5948\u7F8E\u6075\u002D\u0077\u0069\u0074" + "\u0068\u002D\u0053\u0055\u0050\u0045\u0052\u002D\u004D" + "\u004F\u004E\u004B\u0045\u0059\u0053", "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n", }, { // (N) Hello-Another-Way-. "\u0048\u0065\u006C\u006C\u006F\u002D\u0041\u006E\u006F" + "\u0074\u0068\u0065\u0072\u002D\u0057\u0061\u0079\u002D" + "\u305D\u308C\u305E\u308C\u306E\u5834\u6240", "Hello-Another-Way--fc4qua05auwb3674vfr0b", }, { // (O) 2. "\u3072\u3068\u3064\u5C4B\u6839\u306E\u4E0B\u0032", "2-u9tlzr9756bt3uc0v", }, { // (P) MajiKoi5 "\u004D\u0061\u006A\u0069\u3067\u004B\u006F\u0069\u3059" + "\u308B\u0035\u79D2\u524D", "MajiKoi5-783gue6qz075azm5e", }, { // (Q) de "\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0", "de-jg4avhby1noc0d", }, { // (R) "\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067", "d9juau41awczczp", }, { // (S) -> $1.00 <- "\u002D\u003E\u0020\u0024\u0031\u002E\u0030\u0030\u0020" + "\u003C\u002D", "-> $1.00 <--", }, } func TestPunycode(t *testing.T) { for _, tc := range punycodeTestCases { if got, err := decode(tc.encoded); err != nil { t.Errorf("decode(%q): %v", tc.encoded, err) } else if got != tc.s { t.Errorf("decode(%q): got %q, want %q", tc.encoded, got, tc.s) } if got, err := encode("", tc.s); err != nil { t.Errorf(`encode("", %q): %v`, tc.s, err) } else if got != tc.encoded { t.Errorf(`encode("", %q): got %q, want %q`, tc.s, got, tc.encoded) } } } var punycodeErrorTestCases = [...]string{ "decode -", // A sole '-' is invalid. "decode foo\x00bar", // '\x00' is not in [0-9A-Za-z]. "decode foo#bar", // '#' is not in [0-9A-Za-z]. "decode foo\u00A3bar", // '\u00A3' is not in [0-9A-Za-z]. "decode 9", // "9a" decodes to codepoint \u00A3; "9" is truncated. "decode 99999a", // "99999a" decodes to codepoint \U0048A3C1, which is > \U0010FFFF. "decode 9999999999a", // "9999999999a" overflows the int32 calculation. "encode " + strings.Repeat("x", 65536) + "\uff00", // int32 overflow. } func TestPunycodeErrors(t *testing.T) { for _, tc := range punycodeErrorTestCases { var err error switch { case strings.HasPrefix(tc, "decode "): _, err = decode(tc[7:]) case strings.HasPrefix(tc, "encode "): _, err = encode("", tc[7:]) } if err == nil { if len(tc) > 256 { tc = tc[:100] + "..." + tc[len(tc)-100:] } t.Errorf("no error for %s", tc) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/000077500000000000000000000000001264464372400222545ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/iana/000077500000000000000000000000001264464372400231645ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/iana/const.go000066400000000000000000000214361264464372400246470ustar00rootroot00000000000000// go generate gen.go // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA). package iana // import "golang.org/x/net/internal/iana" // Differentiated Services Field Codepoints (DSCP), Updated: 2013-06-25 const ( DiffServCS0 = 0x0 // CS0 DiffServCS1 = 0x20 // CS1 DiffServCS2 = 0x40 // CS2 DiffServCS3 = 0x60 // CS3 DiffServCS4 = 0x80 // CS4 DiffServCS5 = 0xa0 // CS5 DiffServCS6 = 0xc0 // CS6 DiffServCS7 = 0xe0 // CS7 DiffServAF11 = 0x28 // AF11 DiffServAF12 = 0x30 // AF12 DiffServAF13 = 0x38 // AF13 DiffServAF21 = 0x48 // AF21 DiffServAF22 = 0x50 // AF22 DiffServAF23 = 0x58 // AF23 DiffServAF31 = 0x68 // AF31 DiffServAF32 = 0x70 // AF32 DiffServAF33 = 0x78 // AF33 DiffServAF41 = 0x88 // AF41 DiffServAF42 = 0x90 // AF42 DiffServAF43 = 0x98 // AF43 DiffServEFPHB = 0xb8 // EF PHB DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT ) // IPv4 TOS Byte and IPv6 Traffic Class Octet, Updated: 2001-09-06 const ( NotECNTransport = 0x0 // Not-ECT (Not ECN-Capable Transport) ECNTransport1 = 0x1 // ECT(1) (ECN-Capable Transport(1)) ECNTransport0 = 0x2 // ECT(0) (ECN-Capable Transport(0)) CongestionExperienced = 0x3 // CE (Congestion Experienced) ) // Protocol Numbers, Updated: 2015-06-23 const ( ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option ProtocolICMP = 1 // Internet Control Message ProtocolIGMP = 2 // Internet Group Management ProtocolGGP = 3 // Gateway-to-Gateway ProtocolIPv4 = 4 // IPv4 encapsulation ProtocolST = 5 // Stream ProtocolTCP = 6 // Transmission Control ProtocolCBT = 7 // CBT ProtocolEGP = 8 // Exterior Gateway Protocol ProtocolIGP = 9 // any private interior gateway (used by Cisco for their IGRP) ProtocolBBNRCCMON = 10 // BBN RCC Monitoring ProtocolNVPII = 11 // Network Voice Protocol ProtocolPUP = 12 // PUP ProtocolARGUS = 13 // ARGUS ProtocolEMCON = 14 // EMCON ProtocolXNET = 15 // Cross Net Debugger ProtocolCHAOS = 16 // Chaos ProtocolUDP = 17 // User Datagram ProtocolMUX = 18 // Multiplexing ProtocolDCNMEAS = 19 // DCN Measurement Subsystems ProtocolHMP = 20 // Host Monitoring ProtocolPRM = 21 // Packet Radio Measurement ProtocolXNSIDP = 22 // XEROX NS IDP ProtocolTRUNK1 = 23 // Trunk-1 ProtocolTRUNK2 = 24 // Trunk-2 ProtocolLEAF1 = 25 // Leaf-1 ProtocolLEAF2 = 26 // Leaf-2 ProtocolRDP = 27 // Reliable Data Protocol ProtocolIRTP = 28 // Internet Reliable Transaction ProtocolISOTP4 = 29 // ISO Transport Protocol Class 4 ProtocolNETBLT = 30 // Bulk Data Transfer Protocol ProtocolMFENSP = 31 // MFE Network Services Protocol ProtocolMERITINP = 32 // MERIT Internodal Protocol ProtocolDCCP = 33 // Datagram Congestion Control Protocol Protocol3PC = 34 // Third Party Connect Protocol ProtocolIDPR = 35 // Inter-Domain Policy Routing Protocol ProtocolXTP = 36 // XTP ProtocolDDP = 37 // Datagram Delivery Protocol ProtocolIDPRCMTP = 38 // IDPR Control Message Transport Proto ProtocolTPPP = 39 // TP++ Transport Protocol ProtocolIL = 40 // IL Transport Protocol ProtocolIPv6 = 41 // IPv6 encapsulation ProtocolSDRP = 42 // Source Demand Routing Protocol ProtocolIPv6Route = 43 // Routing Header for IPv6 ProtocolIPv6Frag = 44 // Fragment Header for IPv6 ProtocolIDRP = 45 // Inter-Domain Routing Protocol ProtocolRSVP = 46 // Reservation Protocol ProtocolGRE = 47 // Generic Routing Encapsulation ProtocolDSR = 48 // Dynamic Source Routing Protocol ProtocolBNA = 49 // BNA ProtocolESP = 50 // Encap Security Payload ProtocolAH = 51 // Authentication Header ProtocolINLSP = 52 // Integrated Net Layer Security TUBA ProtocolNARP = 54 // NBMA Address Resolution Protocol ProtocolMOBILE = 55 // IP Mobility ProtocolTLSP = 56 // Transport Layer Security Protocol using Kryptonet key management ProtocolSKIP = 57 // SKIP ProtocolIPv6ICMP = 58 // ICMP for IPv6 ProtocolIPv6NoNxt = 59 // No Next Header for IPv6 ProtocolIPv6Opts = 60 // Destination Options for IPv6 ProtocolCFTP = 62 // CFTP ProtocolSATEXPAK = 64 // SATNET and Backroom EXPAK ProtocolKRYPTOLAN = 65 // Kryptolan ProtocolRVD = 66 // MIT Remote Virtual Disk Protocol ProtocolIPPC = 67 // Internet Pluribus Packet Core ProtocolSATMON = 69 // SATNET Monitoring ProtocolVISA = 70 // VISA Protocol ProtocolIPCV = 71 // Internet Packet Core Utility ProtocolCPNX = 72 // Computer Protocol Network Executive ProtocolCPHB = 73 // Computer Protocol Heart Beat ProtocolWSN = 74 // Wang Span Network ProtocolPVP = 75 // Packet Video Protocol ProtocolBRSATMON = 76 // Backroom SATNET Monitoring ProtocolSUNND = 77 // SUN ND PROTOCOL-Temporary ProtocolWBMON = 78 // WIDEBAND Monitoring ProtocolWBEXPAK = 79 // WIDEBAND EXPAK ProtocolISOIP = 80 // ISO Internet Protocol ProtocolVMTP = 81 // VMTP ProtocolSECUREVMTP = 82 // SECURE-VMTP ProtocolVINES = 83 // VINES ProtocolTTP = 84 // Transaction Transport Protocol ProtocolIPTM = 84 // Internet Protocol Traffic Manager ProtocolNSFNETIGP = 85 // NSFNET-IGP ProtocolDGP = 86 // Dissimilar Gateway Protocol ProtocolTCF = 87 // TCF ProtocolEIGRP = 88 // EIGRP ProtocolOSPFIGP = 89 // OSPFIGP ProtocolSpriteRPC = 90 // Sprite RPC Protocol ProtocolLARP = 91 // Locus Address Resolution Protocol ProtocolMTP = 92 // Multicast Transport Protocol ProtocolAX25 = 93 // AX.25 Frames ProtocolIPIP = 94 // IP-within-IP Encapsulation Protocol ProtocolSCCSP = 96 // Semaphore Communications Sec. Pro. ProtocolETHERIP = 97 // Ethernet-within-IP Encapsulation ProtocolENCAP = 98 // Encapsulation Header ProtocolGMTP = 100 // GMTP ProtocolIFMP = 101 // Ipsilon Flow Management Protocol ProtocolPNNI = 102 // PNNI over IP ProtocolPIM = 103 // Protocol Independent Multicast ProtocolARIS = 104 // ARIS ProtocolSCPS = 105 // SCPS ProtocolQNX = 106 // QNX ProtocolAN = 107 // Active Networks ProtocolIPComp = 108 // IP Payload Compression Protocol ProtocolSNP = 109 // Sitara Networks Protocol ProtocolCompaqPeer = 110 // Compaq Peer Protocol ProtocolIPXinIP = 111 // IPX in IP ProtocolVRRP = 112 // Virtual Router Redundancy Protocol ProtocolPGM = 113 // PGM Reliable Transport Protocol ProtocolL2TP = 115 // Layer Two Tunneling Protocol ProtocolDDX = 116 // D-II Data Exchange (DDX) ProtocolIATP = 117 // Interactive Agent Transfer Protocol ProtocolSTP = 118 // Schedule Transfer Protocol ProtocolSRP = 119 // SpectraLink Radio Protocol ProtocolUTI = 120 // UTI ProtocolSMP = 121 // Simple Message Protocol ProtocolPTP = 123 // Performance Transparency Protocol ProtocolISIS = 124 // ISIS over IPv4 ProtocolFIRE = 125 // FIRE ProtocolCRTP = 126 // Combat Radio Transport Protocol ProtocolCRUDP = 127 // Combat Radio User Datagram ProtocolSSCOPMCE = 128 // SSCOPMCE ProtocolIPLT = 129 // IPLT ProtocolSPS = 130 // Secure Packet Shield ProtocolPIPE = 131 // Private IP Encapsulation within IP ProtocolSCTP = 132 // Stream Control Transmission Protocol ProtocolFC = 133 // Fibre Channel ProtocolRSVPE2EIGNORE = 134 // RSVP-E2E-IGNORE ProtocolMobilityHeader = 135 // Mobility Header ProtocolUDPLite = 136 // UDPLite ProtocolMPLSinIP = 137 // MPLS-in-IP ProtocolMANET = 138 // MANET Protocols ProtocolHIP = 139 // Host Identity Protocol ProtocolShim6 = 140 // Shim6 Protocol ProtocolWESP = 141 // Wrapped Encapsulating Security Payload ProtocolROHC = 142 // Robust Header Compression ProtocolReserved = 255 // Reserved ) golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/iana/gen.go000066400000000000000000000150731264464372400242720ustar00rootroot00000000000000// Copyright 2013 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. // +build ignore //go:generate go run gen.go // This program generates internet protocol constants and tables by // reading IANA protocol registries. package main import ( "bytes" "encoding/xml" "fmt" "go/format" "io" "io/ioutil" "net/http" "os" "strconv" "strings" ) var registries = []struct { url string parse func(io.Writer, io.Reader) error }{ { "http://www.iana.org/assignments/dscp-registry/dscp-registry.xml", parseDSCPRegistry, }, { "http://www.iana.org/assignments/ipv4-tos-byte/ipv4-tos-byte.xml", parseTOSTCByte, }, { "http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml", parseProtocolNumbers, }, } func main() { var bb bytes.Buffer fmt.Fprintf(&bb, "// go generate gen.go\n") fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n") fmt.Fprintf(&bb, "// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).\n") fmt.Fprintf(&bb, `package iana // import "golang.org/x/net/internal/iana"`+"\n\n") for _, r := range registries { resp, err := http.Get(r.url) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { fmt.Fprintf(os.Stderr, "got HTTP status code %v for %v\n", resp.StatusCode, r.url) os.Exit(1) } if err := r.parse(&bb, resp.Body); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } fmt.Fprintf(&bb, "\n") } b, err := format.Source(bb.Bytes()) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } if err := ioutil.WriteFile("const.go", b, 0644); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func parseDSCPRegistry(w io.Writer, r io.Reader) error { dec := xml.NewDecoder(r) var dr dscpRegistry if err := dec.Decode(&dr); err != nil { return err } drs := dr.escape() fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated) fmt.Fprintf(w, "const (\n") for _, dr := range drs { fmt.Fprintf(w, "DiffServ%s = %#x", dr.Name, dr.Value) fmt.Fprintf(w, "// %s\n", dr.OrigName) } fmt.Fprintf(w, ")\n") return nil } type dscpRegistry struct { XMLName xml.Name `xml:"registry"` Title string `xml:"title"` Updated string `xml:"updated"` Note string `xml:"note"` RegTitle string `xml:"registry>title"` PoolRecords []struct { Name string `xml:"name"` Space string `xml:"space"` } `xml:"registry>record"` Records []struct { Name string `xml:"name"` Space string `xml:"space"` } `xml:"registry>registry>record"` } type canonDSCPRecord struct { OrigName string Name string Value int } func (drr *dscpRegistry) escape() []canonDSCPRecord { drs := make([]canonDSCPRecord, len(drr.Records)) sr := strings.NewReplacer( "+", "", "-", "", "/", "", ".", "", " ", "", ) for i, dr := range drr.Records { s := strings.TrimSpace(dr.Name) drs[i].OrigName = s drs[i].Name = sr.Replace(s) n, err := strconv.ParseUint(dr.Space, 2, 8) if err != nil { continue } drs[i].Value = int(n) << 2 } return drs } func parseTOSTCByte(w io.Writer, r io.Reader) error { dec := xml.NewDecoder(r) var ttb tosTCByte if err := dec.Decode(&ttb); err != nil { return err } trs := ttb.escape() fmt.Fprintf(w, "// %s, Updated: %s\n", ttb.Title, ttb.Updated) fmt.Fprintf(w, "const (\n") for _, tr := range trs { fmt.Fprintf(w, "%s = %#x", tr.Keyword, tr.Value) fmt.Fprintf(w, "// %s\n", tr.OrigKeyword) } fmt.Fprintf(w, ")\n") return nil } type tosTCByte struct { XMLName xml.Name `xml:"registry"` Title string `xml:"title"` Updated string `xml:"updated"` Note string `xml:"note"` RegTitle string `xml:"registry>title"` Records []struct { Binary string `xml:"binary"` Keyword string `xml:"keyword"` } `xml:"registry>record"` } type canonTOSTCByteRecord struct { OrigKeyword string Keyword string Value int } func (ttb *tosTCByte) escape() []canonTOSTCByteRecord { trs := make([]canonTOSTCByteRecord, len(ttb.Records)) sr := strings.NewReplacer( "Capable", "", "(", "", ")", "", "+", "", "-", "", "/", "", ".", "", " ", "", ) for i, tr := range ttb.Records { s := strings.TrimSpace(tr.Keyword) trs[i].OrigKeyword = s ss := strings.Split(s, " ") if len(ss) > 1 { trs[i].Keyword = strings.Join(ss[1:], " ") } else { trs[i].Keyword = ss[0] } trs[i].Keyword = sr.Replace(trs[i].Keyword) n, err := strconv.ParseUint(tr.Binary, 2, 8) if err != nil { continue } trs[i].Value = int(n) } return trs } func parseProtocolNumbers(w io.Writer, r io.Reader) error { dec := xml.NewDecoder(r) var pn protocolNumbers if err := dec.Decode(&pn); err != nil { return err } prs := pn.escape() prs = append([]canonProtocolRecord{{ Name: "IP", Descr: "IPv4 encapsulation, pseudo protocol number", Value: 0, }}, prs...) fmt.Fprintf(w, "// %s, Updated: %s\n", pn.Title, pn.Updated) fmt.Fprintf(w, "const (\n") for _, pr := range prs { if pr.Name == "" { continue } fmt.Fprintf(w, "Protocol%s = %d", pr.Name, pr.Value) s := pr.Descr if s == "" { s = pr.OrigName } fmt.Fprintf(w, "// %s\n", s) } fmt.Fprintf(w, ")\n") return nil } type protocolNumbers struct { XMLName xml.Name `xml:"registry"` Title string `xml:"title"` Updated string `xml:"updated"` RegTitle string `xml:"registry>title"` Note string `xml:"registry>note"` Records []struct { Value string `xml:"value"` Name string `xml:"name"` Descr string `xml:"description"` } `xml:"registry>record"` } type canonProtocolRecord struct { OrigName string Name string Descr string Value int } func (pn *protocolNumbers) escape() []canonProtocolRecord { prs := make([]canonProtocolRecord, len(pn.Records)) sr := strings.NewReplacer( "-in-", "in", "-within-", "within", "-over-", "over", "+", "P", "-", "", "/", "", ".", "", " ", "", ) for i, pr := range pn.Records { if strings.Contains(pr.Name, "Deprecated") || strings.Contains(pr.Name, "deprecated") { continue } prs[i].OrigName = pr.Name s := strings.TrimSpace(pr.Name) switch pr.Name { case "ISIS over IPv4": prs[i].Name = "ISIS" case "manet": prs[i].Name = "MANET" default: prs[i].Name = sr.Replace(s) } ss := strings.Split(pr.Descr, "\n") for i := range ss { ss[i] = strings.TrimSpace(ss[i]) } if len(ss) > 1 { prs[i].Descr = strings.Join(ss, " ") } else { prs[i].Descr = ss[0] } prs[i].Value, _ = strconv.Atoi(pr.Value) } return prs } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/000077500000000000000000000000001264464372400237425ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/error_posix.go000066400000000000000000000012141264464372400266420ustar00rootroot00000000000000// Copyright 2014 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. // +build darwin dragonfly freebsd linux netbsd openbsd solaris windows package nettest import ( "os" "syscall" ) func protocolNotSupported(err error) bool { switch err := err.(type) { case syscall.Errno: switch err { case syscall.EPROTONOSUPPORT, syscall.ENOPROTOOPT: return true } case *os.SyscallError: switch err := err.Err.(type) { case syscall.Errno: switch err { case syscall.EPROTONOSUPPORT, syscall.ENOPROTOOPT: return true } } } return false } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/error_stub.go000066400000000000000000000004031264464372400264540ustar00rootroot00000000000000// Copyright 2014 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. // +build nacl plan9 package nettest func protocolNotSupported(err error) bool { return false } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/interface.go000066400000000000000000000041771264464372400262420ustar00rootroot00000000000000// Copyright 2012 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 nettest import "net" // IsMulticastCapable reports whether ifi is an IP multicast-capable // network interface. Network must be "ip", "ip4" or "ip6". func IsMulticastCapable(network string, ifi *net.Interface) (net.IP, bool) { switch network { case "ip", "ip4", "ip6": default: return nil, false } if ifi == nil || ifi.Flags&net.FlagUp == 0 || ifi.Flags&net.FlagMulticast == 0 { return nil, false } return hasRoutableIP(network, ifi) } // RoutedInterface returns a network interface that can route IP // traffic and satisfies flags. It returns nil when an appropriate // network interface is not found. Network must be "ip", "ip4" or // "ip6". func RoutedInterface(network string, flags net.Flags) *net.Interface { switch network { case "ip", "ip4", "ip6": default: return nil } ift, err := net.Interfaces() if err != nil { return nil } for _, ifi := range ift { if ifi.Flags&flags != flags { continue } if _, ok := hasRoutableIP(network, &ifi); !ok { continue } return &ifi } return nil } func hasRoutableIP(network string, ifi *net.Interface) (net.IP, bool) { ifat, err := ifi.Addrs() if err != nil { return nil, false } for _, ifa := range ifat { switch ifa := ifa.(type) { case *net.IPAddr: if ip := routableIP(network, ifa.IP); ip != nil { return ip, true } case *net.IPNet: if ip := routableIP(network, ifa.IP); ip != nil { return ip, true } } } return nil, false } func routableIP(network string, ip net.IP) net.IP { if !ip.IsLoopback() && !ip.IsLinkLocalUnicast() && !ip.IsGlobalUnicast() { return nil } switch network { case "ip4": if ip := ip.To4(); ip != nil { return ip } case "ip6": if ip.IsLoopback() { // addressing scope of the loopback address depends on each implementation return nil } if ip := ip.To16(); ip != nil && ip.To4() == nil { return ip } default: if ip := ip.To4(); ip != nil { return ip } if ip := ip.To16(); ip != nil { return ip } } return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/rlimit.go000066400000000000000000000005321264464372400255710ustar00rootroot00000000000000// Copyright 2015 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 nettest const defaultMaxOpenFiles = 256 // MaxOpenFiles returns the maximum number of open files for the // caller's process. func MaxOpenFiles() int { return maxOpenFiles() } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/rlimit_stub.go000066400000000000000000000003761264464372400266340ustar00rootroot00000000000000// Copyright 2015 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. // +build nacl plan9 package nettest func maxOpenFiles() int { return defaultMaxOpenFiles } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/rlimit_unix.go000066400000000000000000000006701264464372400266370ustar00rootroot00000000000000// Copyright 2015 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. // +build darwin dragonfly freebsd linux netbsd openbsd solaris package nettest import "syscall" func maxOpenFiles() int { var rlim syscall.Rlimit if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil { return defaultMaxOpenFiles } return int(rlim.Cur) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/rlimit_windows.go000066400000000000000000000004111264464372400273370ustar00rootroot00000000000000// Copyright 2015 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 nettest func maxOpenFiles() int { return 4 * defaultMaxOpenFiles /* actually it's 16581375 */ } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/stack.go000066400000000000000000000016011264464372400253740ustar00rootroot00000000000000// Copyright 2014 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 nettest provides utilities for IP testing. package nettest // import "golang.org/x/net/internal/nettest" import "net" // SupportsIPv4 reports whether the platform supports IPv4 networking // functionality. func SupportsIPv4() bool { ln, err := net.Listen("tcp4", "127.0.0.1:0") if err != nil { return false } ln.Close() return true } // SupportsIPv6 reports whether the platform supports IPv6 networking // functionality. func SupportsIPv6() bool { ln, err := net.Listen("tcp6", "[::1]:0") if err != nil { return false } ln.Close() return true } // ProtocolNotSupported reports whether err is a protocol not // supported error. func ProtocolNotSupported(err error) bool { return protocolNotSupported(err) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/stack_stub.go000066400000000000000000000006431264464372400264360ustar00rootroot00000000000000// Copyright 2015 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. // +build nacl plan9 package nettest import ( "fmt" "runtime" ) // SupportsRawIPSocket reports whether the platform supports raw IP // sockets. func SupportsRawIPSocket() (string, bool) { return fmt.Sprintf("not supported on %s", runtime.GOOS), false } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/stack_unix.go000066400000000000000000000007771264464372400264540ustar00rootroot00000000000000// Copyright 2015 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. // +build darwin dragonfly freebsd linux netbsd openbsd solaris package nettest import ( "fmt" "os" "runtime" ) // SupportsRawIPSocket reports whether the platform supports raw IP // sockets. func SupportsRawIPSocket() (string, bool) { if os.Getuid() != 0 { return fmt.Sprintf("must be root on %s", runtime.GOOS), false } return "", true } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/nettest/stack_windows.go000066400000000000000000000022211264464372400271450ustar00rootroot00000000000000// Copyright 2015 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 nettest import ( "fmt" "runtime" "syscall" ) // SupportsRawIPSocket reports whether the platform supports raw IP // sockets. func SupportsRawIPSocket() (string, bool) { // From http://msdn.microsoft.com/en-us/library/windows/desktop/ms740548.aspx: // Note: To use a socket of type SOCK_RAW requires administrative privileges. // Users running Winsock applications that use raw sockets must be a member of // the Administrators group on the local computer, otherwise raw socket calls // will fail with an error code of WSAEACCES. On Windows Vista and later, access // for raw sockets is enforced at socket creation. In earlier versions of Windows, // access for raw sockets is enforced during other socket operations. s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, 0) if err == syscall.WSAEACCES { return fmt.Sprintf("no access to raw socket allowed on %s", runtime.GOOS), false } if err != nil { return err.Error(), false } syscall.Closesocket(s) return "", true } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/timeseries/000077500000000000000000000000001264464372400244255ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/timeseries/timeseries.go000066400000000000000000000351271264464372400271350ustar00rootroot00000000000000// Copyright 2015 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 timeseries implements a time series structure for stats collection. package timeseries // import "golang.org/x/net/internal/timeseries" import ( "fmt" "log" "time" ) const ( timeSeriesNumBuckets = 64 minuteHourSeriesNumBuckets = 60 ) var timeSeriesResolutions = []time.Duration{ 1 * time.Second, 10 * time.Second, 1 * time.Minute, 10 * time.Minute, 1 * time.Hour, 6 * time.Hour, 24 * time.Hour, // 1 day 7 * 24 * time.Hour, // 1 week 4 * 7 * 24 * time.Hour, // 4 weeks 16 * 7 * 24 * time.Hour, // 16 weeks } var minuteHourSeriesResolutions = []time.Duration{ 1 * time.Second, 1 * time.Minute, } // An Observable is a kind of data that can be aggregated in a time series. type Observable interface { Multiply(ratio float64) // Multiplies the data in self by a given ratio Add(other Observable) // Adds the data from a different observation to self Clear() // Clears the observation so it can be reused. CopyFrom(other Observable) // Copies the contents of a given observation to self } // Float attaches the methods of Observable to a float64. type Float float64 // NewFloat returns a Float. func NewFloat() Observable { f := Float(0) return &f } // String returns the float as a string. func (f *Float) String() string { return fmt.Sprintf("%g", f.Value()) } // Value returns the float's value. func (f *Float) Value() float64 { return float64(*f) } func (f *Float) Multiply(ratio float64) { *f *= Float(ratio) } func (f *Float) Add(other Observable) { o := other.(*Float) *f += *o } func (f *Float) Clear() { *f = 0 } func (f *Float) CopyFrom(other Observable) { o := other.(*Float) *f = *o } // A Clock tells the current time. type Clock interface { Time() time.Time } type defaultClock int var defaultClockInstance defaultClock func (defaultClock) Time() time.Time { return time.Now() } // Information kept per level. Each level consists of a circular list of // observations. The start of the level may be derived from end and the // len(buckets) * sizeInMillis. type tsLevel struct { oldest int // index to oldest bucketed Observable newest int // index to newest bucketed Observable end time.Time // end timestamp for this level size time.Duration // duration of the bucketed Observable buckets []Observable // collections of observations provider func() Observable // used for creating new Observable } func (l *tsLevel) Clear() { l.oldest = 0 l.newest = len(l.buckets) - 1 l.end = time.Time{} for i := range l.buckets { if l.buckets[i] != nil { l.buckets[i].Clear() l.buckets[i] = nil } } } func (l *tsLevel) InitLevel(size time.Duration, numBuckets int, f func() Observable) { l.size = size l.provider = f l.buckets = make([]Observable, numBuckets) } // Keeps a sequence of levels. Each level is responsible for storing data at // a given resolution. For example, the first level stores data at a one // minute resolution while the second level stores data at a one hour // resolution. // Each level is represented by a sequence of buckets. Each bucket spans an // interval equal to the resolution of the level. New observations are added // to the last bucket. type timeSeries struct { provider func() Observable // make more Observable numBuckets int // number of buckets in each level levels []*tsLevel // levels of bucketed Observable lastAdd time.Time // time of last Observable tracked total Observable // convenient aggregation of all Observable clock Clock // Clock for getting current time pending Observable // observations not yet bucketed pendingTime time.Time // what time are we keeping in pending dirty bool // if there are pending observations } // init initializes a level according to the supplied criteria. func (ts *timeSeries) init(resolutions []time.Duration, f func() Observable, numBuckets int, clock Clock) { ts.provider = f ts.numBuckets = numBuckets ts.clock = clock ts.levels = make([]*tsLevel, len(resolutions)) for i := range resolutions { if i > 0 && resolutions[i-1] >= resolutions[i] { log.Print("timeseries: resolutions must be monotonically increasing") break } newLevel := new(tsLevel) newLevel.InitLevel(resolutions[i], ts.numBuckets, ts.provider) ts.levels[i] = newLevel } ts.Clear() } // Clear removes all observations from the time series. func (ts *timeSeries) Clear() { ts.lastAdd = time.Time{} ts.total = ts.resetObservation(ts.total) ts.pending = ts.resetObservation(ts.pending) ts.pendingTime = time.Time{} ts.dirty = false for i := range ts.levels { ts.levels[i].Clear() } } // Add records an observation at the current time. func (ts *timeSeries) Add(observation Observable) { ts.AddWithTime(observation, ts.clock.Time()) } // AddWithTime records an observation at the specified time. func (ts *timeSeries) AddWithTime(observation Observable, t time.Time) { smallBucketDuration := ts.levels[0].size if t.After(ts.lastAdd) { ts.lastAdd = t } if t.After(ts.pendingTime) { ts.advance(t) ts.mergePendingUpdates() ts.pendingTime = ts.levels[0].end ts.pending.CopyFrom(observation) ts.dirty = true } else if t.After(ts.pendingTime.Add(-1 * smallBucketDuration)) { // The observation is close enough to go into the pending bucket. // This compensates for clock skewing and small scheduling delays // by letting the update stay in the fast path. ts.pending.Add(observation) ts.dirty = true } else { ts.mergeValue(observation, t) } } // mergeValue inserts the observation at the specified time in the past into all levels. func (ts *timeSeries) mergeValue(observation Observable, t time.Time) { for _, level := range ts.levels { index := (ts.numBuckets - 1) - int(level.end.Sub(t)/level.size) if 0 <= index && index < ts.numBuckets { bucketNumber := (level.oldest + index) % ts.numBuckets if level.buckets[bucketNumber] == nil { level.buckets[bucketNumber] = level.provider() } level.buckets[bucketNumber].Add(observation) } } ts.total.Add(observation) } // mergePendingUpdates applies the pending updates into all levels. func (ts *timeSeries) mergePendingUpdates() { if ts.dirty { ts.mergeValue(ts.pending, ts.pendingTime) ts.pending = ts.resetObservation(ts.pending) ts.dirty = false } } // advance cycles the buckets at each level until the latest bucket in // each level can hold the time specified. func (ts *timeSeries) advance(t time.Time) { if !t.After(ts.levels[0].end) { return } for i := 0; i < len(ts.levels); i++ { level := ts.levels[i] if !level.end.Before(t) { break } // If the time is sufficiently far, just clear the level and advance // directly. if !t.Before(level.end.Add(level.size * time.Duration(ts.numBuckets))) { for _, b := range level.buckets { ts.resetObservation(b) } level.end = time.Unix(0, (t.UnixNano()/level.size.Nanoseconds())*level.size.Nanoseconds()) } for t.After(level.end) { level.end = level.end.Add(level.size) level.newest = level.oldest level.oldest = (level.oldest + 1) % ts.numBuckets ts.resetObservation(level.buckets[level.newest]) } t = level.end } } // Latest returns the sum of the num latest buckets from the level. func (ts *timeSeries) Latest(level, num int) Observable { now := ts.clock.Time() if ts.levels[0].end.Before(now) { ts.advance(now) } ts.mergePendingUpdates() result := ts.provider() l := ts.levels[level] index := l.newest for i := 0; i < num; i++ { if l.buckets[index] != nil { result.Add(l.buckets[index]) } if index == 0 { index = ts.numBuckets } index-- } return result } // LatestBuckets returns a copy of the num latest buckets from level. func (ts *timeSeries) LatestBuckets(level, num int) []Observable { if level < 0 || level > len(ts.levels) { log.Print("timeseries: bad level argument: ", level) return nil } if num < 0 || num >= ts.numBuckets { log.Print("timeseries: bad num argument: ", num) return nil } results := make([]Observable, num) now := ts.clock.Time() if ts.levels[0].end.Before(now) { ts.advance(now) } ts.mergePendingUpdates() l := ts.levels[level] index := l.newest for i := 0; i < num; i++ { result := ts.provider() results[i] = result if l.buckets[index] != nil { result.CopyFrom(l.buckets[index]) } if index == 0 { index = ts.numBuckets } index -= 1 } return results } // ScaleBy updates observations by scaling by factor. func (ts *timeSeries) ScaleBy(factor float64) { for _, l := range ts.levels { for i := 0; i < ts.numBuckets; i++ { l.buckets[i].Multiply(factor) } } ts.total.Multiply(factor) ts.pending.Multiply(factor) } // Range returns the sum of observations added over the specified time range. // If start or finish times don't fall on bucket boundaries of the same // level, then return values are approximate answers. func (ts *timeSeries) Range(start, finish time.Time) Observable { return ts.ComputeRange(start, finish, 1)[0] } // Recent returns the sum of observations from the last delta. func (ts *timeSeries) Recent(delta time.Duration) Observable { now := ts.clock.Time() return ts.Range(now.Add(-delta), now) } // Total returns the total of all observations. func (ts *timeSeries) Total() Observable { ts.mergePendingUpdates() return ts.total } // ComputeRange computes a specified number of values into a slice using // the observations recorded over the specified time period. The return // values are approximate if the start or finish times don't fall on the // bucket boundaries at the same level or if the number of buckets spanning // the range is not an integral multiple of num. func (ts *timeSeries) ComputeRange(start, finish time.Time, num int) []Observable { if start.After(finish) { log.Printf("timeseries: start > finish, %v>%v", start, finish) return nil } if num < 0 { log.Printf("timeseries: num < 0, %v", num) return nil } results := make([]Observable, num) for _, l := range ts.levels { if !start.Before(l.end.Add(-l.size * time.Duration(ts.numBuckets))) { ts.extract(l, start, finish, num, results) return results } } // Failed to find a level that covers the desired range. So just // extract from the last level, even if it doesn't cover the entire // desired range. ts.extract(ts.levels[len(ts.levels)-1], start, finish, num, results) return results } // RecentList returns the specified number of values in slice over the most // recent time period of the specified range. func (ts *timeSeries) RecentList(delta time.Duration, num int) []Observable { if delta < 0 { return nil } now := ts.clock.Time() return ts.ComputeRange(now.Add(-delta), now, num) } // extract returns a slice of specified number of observations from a given // level over a given range. func (ts *timeSeries) extract(l *tsLevel, start, finish time.Time, num int, results []Observable) { ts.mergePendingUpdates() srcInterval := l.size dstInterval := finish.Sub(start) / time.Duration(num) dstStart := start srcStart := l.end.Add(-srcInterval * time.Duration(ts.numBuckets)) srcIndex := 0 // Where should scanning start? if dstStart.After(srcStart) { advance := dstStart.Sub(srcStart) / srcInterval srcIndex += int(advance) srcStart = srcStart.Add(advance * srcInterval) } // The i'th value is computed as show below. // interval = (finish/start)/num // i'th value = sum of observation in range // [ start + i * interval, // start + (i + 1) * interval ) for i := 0; i < num; i++ { results[i] = ts.resetObservation(results[i]) dstEnd := dstStart.Add(dstInterval) for srcIndex < ts.numBuckets && srcStart.Before(dstEnd) { srcEnd := srcStart.Add(srcInterval) if srcEnd.After(ts.lastAdd) { srcEnd = ts.lastAdd } if !srcEnd.Before(dstStart) { srcValue := l.buckets[(srcIndex+l.oldest)%ts.numBuckets] if !srcStart.Before(dstStart) && !srcEnd.After(dstEnd) { // dst completely contains src. if srcValue != nil { results[i].Add(srcValue) } } else { // dst partially overlaps src. overlapStart := maxTime(srcStart, dstStart) overlapEnd := minTime(srcEnd, dstEnd) base := srcEnd.Sub(srcStart) fraction := overlapEnd.Sub(overlapStart).Seconds() / base.Seconds() used := ts.provider() if srcValue != nil { used.CopyFrom(srcValue) } used.Multiply(fraction) results[i].Add(used) } if srcEnd.After(dstEnd) { break } } srcIndex++ srcStart = srcStart.Add(srcInterval) } dstStart = dstStart.Add(dstInterval) } } // resetObservation clears the content so the struct may be reused. func (ts *timeSeries) resetObservation(observation Observable) Observable { if observation == nil { observation = ts.provider() } else { observation.Clear() } return observation } // TimeSeries tracks data at granularities from 1 second to 16 weeks. type TimeSeries struct { timeSeries } // NewTimeSeries creates a new TimeSeries using the function provided for creating new Observable. func NewTimeSeries(f func() Observable) *TimeSeries { return NewTimeSeriesWithClock(f, defaultClockInstance) } // NewTimeSeriesWithClock creates a new TimeSeries using the function provided for creating new Observable and the clock for // assigning timestamps. func NewTimeSeriesWithClock(f func() Observable, clock Clock) *TimeSeries { ts := new(TimeSeries) ts.timeSeries.init(timeSeriesResolutions, f, timeSeriesNumBuckets, clock) return ts } // MinuteHourSeries tracks data at granularities of 1 minute and 1 hour. type MinuteHourSeries struct { timeSeries } // NewMinuteHourSeries creates a new MinuteHourSeries using the function provided for creating new Observable. func NewMinuteHourSeries(f func() Observable) *MinuteHourSeries { return NewMinuteHourSeriesWithClock(f, defaultClockInstance) } // NewMinuteHourSeriesWithClock creates a new MinuteHourSeries using the function provided for creating new Observable and the clock for // assigning timestamps. func NewMinuteHourSeriesWithClock(f func() Observable, clock Clock) *MinuteHourSeries { ts := new(MinuteHourSeries) ts.timeSeries.init(minuteHourSeriesResolutions, f, minuteHourSeriesNumBuckets, clock) return ts } func (ts *MinuteHourSeries) Minute() Observable { return ts.timeSeries.Latest(0, 60) } func (ts *MinuteHourSeries) Hour() Observable { return ts.timeSeries.Latest(1, 60) } func minTime(a, b time.Time) time.Time { if a.Before(b) { return a } return b } func maxTime(a, b time.Time) time.Time { if a.After(b) { return a } return b } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/internal/timeseries/timeseries_test.go000066400000000000000000000107111264464372400301640ustar00rootroot00000000000000// Copyright 2015 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 timeseries import ( "math" "testing" "time" ) func isNear(x *Float, y float64, tolerance float64) bool { return math.Abs(x.Value()-y) < tolerance } func isApproximate(x *Float, y float64) bool { return isNear(x, y, 1e-2) } func checkApproximate(t *testing.T, o Observable, y float64) { x := o.(*Float) if !isApproximate(x, y) { t.Errorf("Wanted %g, got %g", y, x.Value()) } } func checkNear(t *testing.T, o Observable, y, tolerance float64) { x := o.(*Float) if !isNear(x, y, tolerance) { t.Errorf("Wanted %g +- %g, got %g", y, tolerance, x.Value()) } } var baseTime = time.Date(2013, 1, 1, 0, 0, 0, 0, time.UTC) func tu(s int64) time.Time { return baseTime.Add(time.Duration(s) * time.Second) } func tu2(s int64, ns int64) time.Time { return baseTime.Add(time.Duration(s)*time.Second + time.Duration(ns)*time.Nanosecond) } func TestBasicTimeSeries(t *testing.T) { ts := NewTimeSeries(NewFloat) fo := new(Float) *fo = Float(10) ts.AddWithTime(fo, tu(1)) ts.AddWithTime(fo, tu(1)) ts.AddWithTime(fo, tu(1)) ts.AddWithTime(fo, tu(1)) checkApproximate(t, ts.Range(tu(0), tu(1)), 40) checkApproximate(t, ts.Total(), 40) ts.AddWithTime(fo, tu(3)) ts.AddWithTime(fo, tu(3)) ts.AddWithTime(fo, tu(3)) checkApproximate(t, ts.Range(tu(0), tu(2)), 40) checkApproximate(t, ts.Range(tu(2), tu(4)), 30) checkApproximate(t, ts.Total(), 70) ts.AddWithTime(fo, tu(1)) ts.AddWithTime(fo, tu(1)) checkApproximate(t, ts.Range(tu(0), tu(2)), 60) checkApproximate(t, ts.Range(tu(2), tu(4)), 30) checkApproximate(t, ts.Total(), 90) *fo = Float(100) ts.AddWithTime(fo, tu(100)) checkApproximate(t, ts.Range(tu(99), tu(100)), 100) checkApproximate(t, ts.Range(tu(0), tu(4)), 36) checkApproximate(t, ts.Total(), 190) *fo = Float(10) ts.AddWithTime(fo, tu(1)) ts.AddWithTime(fo, tu(1)) checkApproximate(t, ts.Range(tu(0), tu(4)), 44) checkApproximate(t, ts.Range(tu(37), tu2(100, 100e6)), 100) checkApproximate(t, ts.Range(tu(50), tu2(100, 100e6)), 100) checkApproximate(t, ts.Range(tu(99), tu2(100, 100e6)), 100) checkApproximate(t, ts.Total(), 210) for i, l := range ts.ComputeRange(tu(36), tu(100), 64) { if i == 63 { checkApproximate(t, l, 100) } else { checkApproximate(t, l, 0) } } checkApproximate(t, ts.Range(tu(0), tu(100)), 210) checkApproximate(t, ts.Range(tu(10), tu(100)), 100) for i, l := range ts.ComputeRange(tu(0), tu(100), 100) { if i < 10 { checkApproximate(t, l, 11) } else if i >= 90 { checkApproximate(t, l, 10) } else { checkApproximate(t, l, 0) } } } func TestFloat(t *testing.T) { f := Float(1) if g, w := f.String(), "1"; g != w { t.Errorf("Float(1).String = %q; want %q", g, w) } f2 := Float(2) var o Observable = &f2 f.Add(o) if g, w := f.Value(), 3.0; g != w { t.Errorf("Float post-add = %v; want %v", g, w) } f.Multiply(2) if g, w := f.Value(), 6.0; g != w { t.Errorf("Float post-multiply = %v; want %v", g, w) } f.Clear() if g, w := f.Value(), 0.0; g != w { t.Errorf("Float post-clear = %v; want %v", g, w) } f.CopyFrom(&f2) if g, w := f.Value(), 2.0; g != w { t.Errorf("Float post-CopyFrom = %v; want %v", g, w) } } type mockClock struct { time time.Time } func (m *mockClock) Time() time.Time { return m.time } func (m *mockClock) Set(t time.Time) { m.time = t } const buckets = 6 var testResolutions = []time.Duration{ 10 * time.Second, // level holds one minute of observations 100 * time.Second, // level holds ten minutes of observations 10 * time.Minute, // level holds one hour of observations } // TestTimeSeries uses a small number of buckets to force a higher // error rate on approximations from the timeseries. type TestTimeSeries struct { timeSeries } func TestExpectedErrorRate(t *testing.T) { ts := new(TestTimeSeries) fake := new(mockClock) fake.Set(time.Now()) ts.timeSeries.init(testResolutions, NewFloat, buckets, fake) for i := 1; i <= 61*61; i++ { fake.Set(fake.Time().Add(1 * time.Second)) ob := Float(1) ts.AddWithTime(&ob, fake.Time()) // The results should be accurate within one missing bucket (1/6) of the observations recorded. checkNear(t, ts.Latest(0, buckets), min(float64(i), 60), 10) checkNear(t, ts.Latest(1, buckets), min(float64(i), 600), 100) checkNear(t, ts.Latest(2, buckets), min(float64(i), 3600), 600) } } func min(a, b float64) float64 { if a < b { return a } return b } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/000077500000000000000000000000001264464372400213225ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/control.go000066400000000000000000000042511264464372400233330ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import ( "fmt" "net" "sync" ) type rawOpt struct { sync.RWMutex cflags ControlFlags } func (c *rawOpt) set(f ControlFlags) { c.cflags |= f } func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f } func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 } type ControlFlags uint const ( FlagTTL ControlFlags = 1 << iota // pass the TTL on the received packet FlagSrc // pass the source address on the received packet FlagDst // pass the destination address on the received packet FlagInterface // pass the interface index on the received packet ) // A ControlMessage represents per packet basis IP-level socket options. type ControlMessage struct { // Receiving socket options: SetControlMessage allows to // receive the options from the protocol stack using ReadFrom // method of PacketConn or RawConn. // // Specifying socket options: ControlMessage for WriteTo // method of PacketConn or RawConn allows to send the options // to the protocol stack. // TTL int // time-to-live, receiving only Src net.IP // source address, specifying only Dst net.IP // destination address, receiving only IfIndex int // interface index, must be 1 <= value when specifying } func (cm *ControlMessage) String() string { if cm == nil { return "" } return fmt.Sprintf("ttl=%d src=%v dst=%v ifindex=%d", cm.TTL, cm.Src, cm.Dst, cm.IfIndex) } // Ancillary data socket options const ( ctlTTL = iota // header field ctlSrc // header field ctlDst // header field ctlInterface // inbound or outbound interface ctlPacketInfo // inbound or outbound packet path ctlMax ) // A ctlOpt represents a binding for ancillary data socket option. type ctlOpt struct { name int // option name, must be equal or greater than 1 length int // option length marshal func([]byte, *ControlMessage) []byte parse func(*ControlMessage, []byte) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/control_bsd.go000066400000000000000000000020271264464372400241620ustar00rootroot00000000000000// Copyright 2012 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. // +build darwin dragonfly freebsd netbsd openbsd package ipv4 import ( "net" "syscall" "unsafe" "golang.org/x/net/internal/iana" ) func marshalDst(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIP m.Type = sysIP_RECVDSTADDR m.SetLen(syscall.CmsgLen(net.IPv4len)) return b[syscall.CmsgSpace(net.IPv4len):] } func parseDst(cm *ControlMessage, b []byte) { cm.Dst = b[:net.IPv4len] } func marshalInterface(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIP m.Type = sysIP_RECVIF m.SetLen(syscall.CmsgLen(syscall.SizeofSockaddrDatalink)) return b[syscall.CmsgSpace(syscall.SizeofSockaddrDatalink):] } func parseInterface(cm *ControlMessage, b []byte) { sadl := (*syscall.SockaddrDatalink)(unsafe.Pointer(&b[0])) cm.IfIndex = int(sadl.Index) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/control_pktinfo.go000066400000000000000000000015761264464372400250740ustar00rootroot00000000000000// Copyright 2014 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. // +build darwin linux package ipv4 import ( "syscall" "unsafe" "golang.org/x/net/internal/iana" ) func marshalPacketInfo(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIP m.Type = sysIP_PKTINFO m.SetLen(syscall.CmsgLen(sysSizeofInetPktinfo)) if cm != nil { pi := (*sysInetPktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)])) if ip := cm.Src.To4(); ip != nil { copy(pi.Spec_dst[:], ip) } if cm.IfIndex > 0 { pi.setIfindex(cm.IfIndex) } } return b[syscall.CmsgSpace(sysSizeofInetPktinfo):] } func parsePacketInfo(cm *ControlMessage, b []byte) { pi := (*sysInetPktinfo)(unsafe.Pointer(&b[0])) cm.IfIndex = int(pi.Ifindex) cm.Dst = pi.Addr[:] } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/control_stub.go000066400000000000000000000010241264464372400243630ustar00rootroot00000000000000// Copyright 2012 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. // +build nacl plan9 solaris package ipv4 func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { return errOpNoSupport } func newControlMessage(opt *rawOpt) []byte { return nil } func parseControlMessage(b []byte) (*ControlMessage, error) { return nil, errOpNoSupport } func marshalControlMessage(cm *ControlMessage) []byte { return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/control_unix.go000066400000000000000000000077171264464372400244100ustar00rootroot00000000000000// Copyright 2012 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. // +build darwin dragonfly freebsd linux netbsd openbsd package ipv4 import ( "os" "syscall" "unsafe" "golang.org/x/net/internal/iana" ) func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { opt.Lock() defer opt.Unlock() if cf&FlagTTL != 0 && sockOpts[ssoReceiveTTL].name > 0 { if err := setInt(fd, &sockOpts[ssoReceiveTTL], boolint(on)); err != nil { return err } if on { opt.set(FlagTTL) } else { opt.clear(FlagTTL) } } if sockOpts[ssoPacketInfo].name > 0 { if cf&(FlagSrc|FlagDst|FlagInterface) != 0 { if err := setInt(fd, &sockOpts[ssoPacketInfo], boolint(on)); err != nil { return err } if on { opt.set(cf & (FlagSrc | FlagDst | FlagInterface)) } else { opt.clear(cf & (FlagSrc | FlagDst | FlagInterface)) } } } else { if cf&FlagDst != 0 && sockOpts[ssoReceiveDst].name > 0 { if err := setInt(fd, &sockOpts[ssoReceiveDst], boolint(on)); err != nil { return err } if on { opt.set(FlagDst) } else { opt.clear(FlagDst) } } if cf&FlagInterface != 0 && sockOpts[ssoReceiveInterface].name > 0 { if err := setInt(fd, &sockOpts[ssoReceiveInterface], boolint(on)); err != nil { return err } if on { opt.set(FlagInterface) } else { opt.clear(FlagInterface) } } } return nil } func newControlMessage(opt *rawOpt) (oob []byte) { opt.RLock() var l int if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 { l += syscall.CmsgSpace(ctlOpts[ctlTTL].length) } if ctlOpts[ctlPacketInfo].name > 0 { if opt.isset(FlagSrc | FlagDst | FlagInterface) { l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length) } } else { if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 { l += syscall.CmsgSpace(ctlOpts[ctlDst].length) } if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 { l += syscall.CmsgSpace(ctlOpts[ctlInterface].length) } } if l > 0 { oob = make([]byte, l) b := oob if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 { b = ctlOpts[ctlTTL].marshal(b, nil) } if ctlOpts[ctlPacketInfo].name > 0 { if opt.isset(FlagSrc | FlagDst | FlagInterface) { b = ctlOpts[ctlPacketInfo].marshal(b, nil) } } else { if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 { b = ctlOpts[ctlDst].marshal(b, nil) } if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 { b = ctlOpts[ctlInterface].marshal(b, nil) } } } opt.RUnlock() return } func parseControlMessage(b []byte) (*ControlMessage, error) { if len(b) == 0 { return nil, nil } cmsgs, err := syscall.ParseSocketControlMessage(b) if err != nil { return nil, os.NewSyscallError("parse socket control message", err) } cm := &ControlMessage{} for _, m := range cmsgs { if m.Header.Level != iana.ProtocolIP { continue } switch int(m.Header.Type) { case ctlOpts[ctlTTL].name: ctlOpts[ctlTTL].parse(cm, m.Data[:]) case ctlOpts[ctlDst].name: ctlOpts[ctlDst].parse(cm, m.Data[:]) case ctlOpts[ctlInterface].name: ctlOpts[ctlInterface].parse(cm, m.Data[:]) case ctlOpts[ctlPacketInfo].name: ctlOpts[ctlPacketInfo].parse(cm, m.Data[:]) } } return cm, nil } func marshalControlMessage(cm *ControlMessage) (oob []byte) { if cm == nil { return nil } var l int pktinfo := false if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To4() != nil || cm.IfIndex > 0) { pktinfo = true l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length) } if l > 0 { oob = make([]byte, l) b := oob if pktinfo { b = ctlOpts[ctlPacketInfo].marshal(b, cm) } } return } func marshalTTL(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIP m.Type = sysIP_RECVTTL m.SetLen(syscall.CmsgLen(1)) return b[syscall.CmsgSpace(1):] } func parseTTL(cm *ControlMessage, b []byte) { cm.TTL = int(*(*byte)(unsafe.Pointer(&b[:1][0]))) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/control_windows.go000066400000000000000000000012271264464372400251050ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import "syscall" func setControlMessage(fd syscall.Handle, opt *rawOpt, cf ControlFlags, on bool) error { // TODO(mikio): implement this return syscall.EWINDOWS } func newControlMessage(opt *rawOpt) []byte { // TODO(mikio): implement this return nil } func parseControlMessage(b []byte) (*ControlMessage, error) { // TODO(mikio): implement this return nil, syscall.EWINDOWS } func marshalControlMessage(cm *ControlMessage) []byte { // TODO(mikio): implement this return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/defs_darwin.go000066400000000000000000000047061264464372400241450ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in_addr [4]byte /* in_addr */ package ipv4 /* #include #include */ import "C" const ( sysIP_OPTIONS = C.IP_OPTIONS sysIP_HDRINCL = C.IP_HDRINCL sysIP_TOS = C.IP_TOS sysIP_TTL = C.IP_TTL sysIP_RECVOPTS = C.IP_RECVOPTS sysIP_RECVRETOPTS = C.IP_RECVRETOPTS sysIP_RECVDSTADDR = C.IP_RECVDSTADDR sysIP_RETOPTS = C.IP_RETOPTS sysIP_RECVIF = C.IP_RECVIF sysIP_STRIPHDR = C.IP_STRIPHDR sysIP_RECVTTL = C.IP_RECVTTL sysIP_BOUND_IF = C.IP_BOUND_IF sysIP_PKTINFO = C.IP_PKTINFO sysIP_RECVPKTINFO = C.IP_RECVPKTINFO sysIP_MULTICAST_IF = C.IP_MULTICAST_IF sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP sysIP_MULTICAST_VIF = C.IP_MULTICAST_VIF sysIP_MULTICAST_IFINDEX = C.IP_MULTICAST_IFINDEX sysIP_ADD_SOURCE_MEMBERSHIP = C.IP_ADD_SOURCE_MEMBERSHIP sysIP_DROP_SOURCE_MEMBERSHIP = C.IP_DROP_SOURCE_MEMBERSHIP sysIP_BLOCK_SOURCE = C.IP_BLOCK_SOURCE sysIP_UNBLOCK_SOURCE = C.IP_UNBLOCK_SOURCE sysMCAST_JOIN_GROUP = C.MCAST_JOIN_GROUP sysMCAST_LEAVE_GROUP = C.MCAST_LEAVE_GROUP sysMCAST_JOIN_SOURCE_GROUP = C.MCAST_JOIN_SOURCE_GROUP sysMCAST_LEAVE_SOURCE_GROUP = C.MCAST_LEAVE_SOURCE_GROUP sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE sysSizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage sysSizeofSockaddrInet = C.sizeof_struct_sockaddr_in sysSizeofInetPktinfo = C.sizeof_struct_in_pktinfo sysSizeofIPMreq = C.sizeof_struct_ip_mreq sysSizeofIPMreqn = C.sizeof_struct_ip_mreqn sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source sysSizeofGroupReq = C.sizeof_struct_group_req sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req ) type sysSockaddrStorage C.struct_sockaddr_storage type sysSockaddrInet C.struct_sockaddr_in type sysInetPktinfo C.struct_in_pktinfo type sysIPMreq C.struct_ip_mreq type sysIPMreqn C.struct_ip_mreqn type sysIPMreqSource C.struct_ip_mreq_source type sysGroupReq C.struct_group_req type sysGroupSourceReq C.struct_group_source_req golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/defs_dragonfly.go000066400000000000000000000017261264464372400246450ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in_addr [4]byte /* in_addr */ package ipv4 /* #include */ import "C" const ( sysIP_OPTIONS = C.IP_OPTIONS sysIP_HDRINCL = C.IP_HDRINCL sysIP_TOS = C.IP_TOS sysIP_TTL = C.IP_TTL sysIP_RECVOPTS = C.IP_RECVOPTS sysIP_RECVRETOPTS = C.IP_RECVRETOPTS sysIP_RECVDSTADDR = C.IP_RECVDSTADDR sysIP_RETOPTS = C.IP_RETOPTS sysIP_RECVIF = C.IP_RECVIF sysIP_RECVTTL = C.IP_RECVTTL sysIP_MULTICAST_IF = C.IP_MULTICAST_IF sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP sysIP_MULTICAST_VIF = C.IP_MULTICAST_VIF sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP sysSizeofIPMreq = C.sizeof_struct_ip_mreq ) type sysIPMreq C.struct_ip_mreq golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/defs_freebsd.go000066400000000000000000000045631264464372400242740ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in_addr [4]byte /* in_addr */ package ipv4 /* #include #include */ import "C" const ( sysIP_OPTIONS = C.IP_OPTIONS sysIP_HDRINCL = C.IP_HDRINCL sysIP_TOS = C.IP_TOS sysIP_TTL = C.IP_TTL sysIP_RECVOPTS = C.IP_RECVOPTS sysIP_RECVRETOPTS = C.IP_RECVRETOPTS sysIP_RECVDSTADDR = C.IP_RECVDSTADDR sysIP_SENDSRCADDR = C.IP_SENDSRCADDR sysIP_RETOPTS = C.IP_RETOPTS sysIP_RECVIF = C.IP_RECVIF sysIP_ONESBCAST = C.IP_ONESBCAST sysIP_BINDANY = C.IP_BINDANY sysIP_RECVTTL = C.IP_RECVTTL sysIP_MINTTL = C.IP_MINTTL sysIP_DONTFRAG = C.IP_DONTFRAG sysIP_RECVTOS = C.IP_RECVTOS sysIP_MULTICAST_IF = C.IP_MULTICAST_IF sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP sysIP_MULTICAST_VIF = C.IP_MULTICAST_VIF sysIP_ADD_SOURCE_MEMBERSHIP = C.IP_ADD_SOURCE_MEMBERSHIP sysIP_DROP_SOURCE_MEMBERSHIP = C.IP_DROP_SOURCE_MEMBERSHIP sysIP_BLOCK_SOURCE = C.IP_BLOCK_SOURCE sysIP_UNBLOCK_SOURCE = C.IP_UNBLOCK_SOURCE sysMCAST_JOIN_GROUP = C.MCAST_JOIN_GROUP sysMCAST_LEAVE_GROUP = C.MCAST_LEAVE_GROUP sysMCAST_JOIN_SOURCE_GROUP = C.MCAST_JOIN_SOURCE_GROUP sysMCAST_LEAVE_SOURCE_GROUP = C.MCAST_LEAVE_SOURCE_GROUP sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE sysSizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage sysSizeofSockaddrInet = C.sizeof_struct_sockaddr_in sysSizeofIPMreq = C.sizeof_struct_ip_mreq sysSizeofIPMreqn = C.sizeof_struct_ip_mreqn sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source sysSizeofGroupReq = C.sizeof_struct_group_req sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req ) type sysSockaddrStorage C.struct_sockaddr_storage type sysSockaddrInet C.struct_sockaddr_in type sysIPMreq C.struct_ip_mreq type sysIPMreqn C.struct_ip_mreqn type sysIPMreqSource C.struct_ip_mreq_source type sysGroupReq C.struct_group_req type sysGroupSourceReq C.struct_group_source_req golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/defs_linux.go000066400000000000000000000074501264464372400240170ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in_addr [4]byte /* in_addr */ package ipv4 /* #include #include #include #include */ import "C" const ( sysIP_TOS = C.IP_TOS sysIP_TTL = C.IP_TTL sysIP_HDRINCL = C.IP_HDRINCL sysIP_OPTIONS = C.IP_OPTIONS sysIP_ROUTER_ALERT = C.IP_ROUTER_ALERT sysIP_RECVOPTS = C.IP_RECVOPTS sysIP_RETOPTS = C.IP_RETOPTS sysIP_PKTINFO = C.IP_PKTINFO sysIP_PKTOPTIONS = C.IP_PKTOPTIONS sysIP_MTU_DISCOVER = C.IP_MTU_DISCOVER sysIP_RECVERR = C.IP_RECVERR sysIP_RECVTTL = C.IP_RECVTTL sysIP_RECVTOS = C.IP_RECVTOS sysIP_MTU = C.IP_MTU sysIP_FREEBIND = C.IP_FREEBIND sysIP_TRANSPARENT = C.IP_TRANSPARENT sysIP_RECVRETOPTS = C.IP_RECVRETOPTS sysIP_ORIGDSTADDR = C.IP_ORIGDSTADDR sysIP_RECVORIGDSTADDR = C.IP_RECVORIGDSTADDR sysIP_MINTTL = C.IP_MINTTL sysIP_NODEFRAG = C.IP_NODEFRAG sysIP_UNICAST_IF = C.IP_UNICAST_IF sysIP_MULTICAST_IF = C.IP_MULTICAST_IF sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP sysIP_UNBLOCK_SOURCE = C.IP_UNBLOCK_SOURCE sysIP_BLOCK_SOURCE = C.IP_BLOCK_SOURCE sysIP_ADD_SOURCE_MEMBERSHIP = C.IP_ADD_SOURCE_MEMBERSHIP sysIP_DROP_SOURCE_MEMBERSHIP = C.IP_DROP_SOURCE_MEMBERSHIP sysIP_MSFILTER = C.IP_MSFILTER sysMCAST_JOIN_GROUP = C.MCAST_JOIN_GROUP sysMCAST_LEAVE_GROUP = C.MCAST_LEAVE_GROUP sysMCAST_JOIN_SOURCE_GROUP = C.MCAST_JOIN_SOURCE_GROUP sysMCAST_LEAVE_SOURCE_GROUP = C.MCAST_LEAVE_SOURCE_GROUP sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE sysMCAST_MSFILTER = C.MCAST_MSFILTER sysIP_MULTICAST_ALL = C.IP_MULTICAST_ALL //sysIP_PMTUDISC_DONT = C.IP_PMTUDISC_DONT //sysIP_PMTUDISC_WANT = C.IP_PMTUDISC_WANT //sysIP_PMTUDISC_DO = C.IP_PMTUDISC_DO //sysIP_PMTUDISC_PROBE = C.IP_PMTUDISC_PROBE //sysIP_PMTUDISC_INTERFACE = C.IP_PMTUDISC_INTERFACE //sysIP_PMTUDISC_OMIT = C.IP_PMTUDISC_OMIT sysICMP_FILTER = C.ICMP_FILTER sysSO_EE_ORIGIN_NONE = C.SO_EE_ORIGIN_NONE sysSO_EE_ORIGIN_LOCAL = C.SO_EE_ORIGIN_LOCAL sysSO_EE_ORIGIN_ICMP = C.SO_EE_ORIGIN_ICMP sysSO_EE_ORIGIN_ICMP6 = C.SO_EE_ORIGIN_ICMP6 sysSO_EE_ORIGIN_TXSTATUS = C.SO_EE_ORIGIN_TXSTATUS sysSO_EE_ORIGIN_TIMESTAMPING = C.SO_EE_ORIGIN_TIMESTAMPING sysSizeofKernelSockaddrStorage = C.sizeof_struct___kernel_sockaddr_storage sysSizeofSockaddrInet = C.sizeof_struct_sockaddr_in sysSizeofInetPktinfo = C.sizeof_struct_in_pktinfo sysSizeofSockExtendedErr = C.sizeof_struct_sock_extended_err sysSizeofIPMreq = C.sizeof_struct_ip_mreq sysSizeofIPMreqn = C.sizeof_struct_ip_mreqn sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source sysSizeofGroupReq = C.sizeof_struct_group_req sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req sysSizeofICMPFilter = C.sizeof_struct_icmp_filter ) type sysKernelSockaddrStorage C.struct___kernel_sockaddr_storage type sysSockaddrInet C.struct_sockaddr_in type sysInetPktinfo C.struct_in_pktinfo type sysSockExtendedErr C.struct_sock_extended_err type sysIPMreq C.struct_ip_mreq type sysIPMreqn C.struct_ip_mreqn type sysIPMreqSource C.struct_ip_mreq_source type sysGroupReq C.struct_group_req type sysGroupSourceReq C.struct_group_source_req type sysICMPFilter C.struct_icmp_filter golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/defs_netbsd.go000066400000000000000000000016521264464372400241350ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in_addr [4]byte /* in_addr */ package ipv4 /* #include */ import "C" const ( sysIP_OPTIONS = C.IP_OPTIONS sysIP_HDRINCL = C.IP_HDRINCL sysIP_TOS = C.IP_TOS sysIP_TTL = C.IP_TTL sysIP_RECVOPTS = C.IP_RECVOPTS sysIP_RECVRETOPTS = C.IP_RECVRETOPTS sysIP_RECVDSTADDR = C.IP_RECVDSTADDR sysIP_RETOPTS = C.IP_RETOPTS sysIP_RECVIF = C.IP_RECVIF sysIP_RECVTTL = C.IP_RECVTTL sysIP_MULTICAST_IF = C.IP_MULTICAST_IF sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP sysSizeofIPMreq = C.sizeof_struct_ip_mreq ) type sysIPMreq C.struct_ip_mreq golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/defs_openbsd.go000066400000000000000000000016521264464372400243100ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in_addr [4]byte /* in_addr */ package ipv4 /* #include */ import "C" const ( sysIP_OPTIONS = C.IP_OPTIONS sysIP_HDRINCL = C.IP_HDRINCL sysIP_TOS = C.IP_TOS sysIP_TTL = C.IP_TTL sysIP_RECVOPTS = C.IP_RECVOPTS sysIP_RECVRETOPTS = C.IP_RECVRETOPTS sysIP_RECVDSTADDR = C.IP_RECVDSTADDR sysIP_RETOPTS = C.IP_RETOPTS sysIP_RECVIF = C.IP_RECVIF sysIP_RECVTTL = C.IP_RECVTTL sysIP_MULTICAST_IF = C.IP_MULTICAST_IF sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP sysSizeofIPMreq = C.sizeof_struct_ip_mreq ) type sysIPMreq C.struct_ip_mreq golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/defs_solaris.go000066400000000000000000000033371264464372400243340ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in_addr [4]byte /* in_addr */ package ipv4 /* #include */ import "C" const ( sysIP_OPTIONS = C.IP_OPTIONS sysIP_HDRINCL = C.IP_HDRINCL sysIP_TOS = C.IP_TOS sysIP_TTL = C.IP_TTL sysIP_RECVOPTS = C.IP_RECVOPTS sysIP_RECVRETOPTS = C.IP_RECVRETOPTS sysIP_RECVDSTADDR = C.IP_RECVDSTADDR sysIP_RETOPTS = C.IP_RETOPTS sysIP_RECVIF = C.IP_RECVIF sysIP_RECVSLLA = C.IP_RECVSLLA sysIP_RECVTTL = C.IP_RECVTTL sysIP_NEXTHOP = C.IP_NEXTHOP sysIP_PKTINFO = C.IP_PKTINFO sysIP_RECVPKTINFO = C.IP_RECVPKTINFO sysIP_DONTFRAG = C.IP_DONTFRAG sysIP_BOUND_IF = C.IP_BOUND_IF sysIP_UNSPEC_SRC = C.IP_UNSPEC_SRC sysIP_BROADCAST_TTL = C.IP_BROADCAST_TTL sysIP_DHCPINIT_IF = C.IP_DHCPINIT_IF sysIP_MULTICAST_IF = C.IP_MULTICAST_IF sysIP_MULTICAST_TTL = C.IP_MULTICAST_TTL sysIP_MULTICAST_LOOP = C.IP_MULTICAST_LOOP sysIP_ADD_MEMBERSHIP = C.IP_ADD_MEMBERSHIP sysIP_DROP_MEMBERSHIP = C.IP_DROP_MEMBERSHIP sysIP_BLOCK_SOURCE = C.IP_BLOCK_SOURCE sysIP_UNBLOCK_SOURCE = C.IP_UNBLOCK_SOURCE sysIP_ADD_SOURCE_MEMBERSHIP = C.IP_ADD_SOURCE_MEMBERSHIP sysIP_DROP_SOURCE_MEMBERSHIP = C.IP_DROP_SOURCE_MEMBERSHIP sysSizeofInetPktinfo = C.sizeof_struct_in_pktinfo sysSizeofIPMreq = C.sizeof_struct_ip_mreq sysSizeofIPMreqSource = C.sizeof_struct_ip_mreq_source ) type sysInetPktinfo C.struct_in_pktinfo type sysIPMreq C.struct_ip_mreq type sysIPMreqSource C.struct_ip_mreq_source golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/dgramopt_posix.go000066400000000000000000000145341264464372400247170ustar00rootroot00000000000000// Copyright 2012 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. // +build darwin dragonfly freebsd linux netbsd openbsd windows package ipv4 import ( "net" "syscall" ) // MulticastTTL returns the time-to-live field value for outgoing // multicast packets. func (c *dgramOpt) MulticastTTL() (int, error) { if !c.ok() { return 0, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return 0, err } return getInt(fd, &sockOpts[ssoMulticastTTL]) } // SetMulticastTTL sets the time-to-live field value for future // outgoing multicast packets. func (c *dgramOpt) SetMulticastTTL(ttl int) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setInt(fd, &sockOpts[ssoMulticastTTL], ttl) } // MulticastInterface returns the default interface for multicast // packet transmissions. func (c *dgramOpt) MulticastInterface() (*net.Interface, error) { if !c.ok() { return nil, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return nil, err } return getInterface(fd, &sockOpts[ssoMulticastInterface]) } // SetMulticastInterface sets the default interface for future // multicast packet transmissions. func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setInterface(fd, &sockOpts[ssoMulticastInterface], ifi) } // MulticastLoopback reports whether transmitted multicast packets // should be copied and send back to the originator. func (c *dgramOpt) MulticastLoopback() (bool, error) { if !c.ok() { return false, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return false, err } on, err := getInt(fd, &sockOpts[ssoMulticastLoopback]) if err != nil { return false, err } return on == 1, nil } // SetMulticastLoopback sets whether transmitted multicast packets // should be copied and send back to the originator. func (c *dgramOpt) SetMulticastLoopback(on bool) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setInt(fd, &sockOpts[ssoMulticastLoopback], boolint(on)) } // JoinGroup joins the group address group on the interface ifi. // By default all sources that can cast data to group are accepted. // It's possible to mute and unmute data transmission from a specific // source by using ExcludeSourceSpecificGroup and // IncludeSourceSpecificGroup. // JoinGroup uses the system assigned multicast interface when ifi is // nil, although this is not recommended because the assignment // depends on platforms and sometimes it might require routing // configuration. func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP4(group) if grp == nil { return errMissingAddress } return setGroup(fd, &sockOpts[ssoJoinGroup], ifi, grp) } // LeaveGroup leaves the group address group on the interface ifi // regardless of whether the group is any-source group or // source-specific group. func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP4(group) if grp == nil { return errMissingAddress } return setGroup(fd, &sockOpts[ssoLeaveGroup], ifi, grp) } // JoinSourceSpecificGroup joins the source-specific group comprising // group and source on the interface ifi. // JoinSourceSpecificGroup uses the system assigned multicast // interface when ifi is nil, although this is not recommended because // the assignment depends on platforms and sometimes it might require // routing configuration. func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP4(group) if grp == nil { return errMissingAddress } src := netAddrToIP4(source) if src == nil { return errMissingAddress } return setSourceGroup(fd, &sockOpts[ssoJoinSourceGroup], ifi, grp, src) } // LeaveSourceSpecificGroup leaves the source-specific group on the // interface ifi. func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP4(group) if grp == nil { return errMissingAddress } src := netAddrToIP4(source) if src == nil { return errMissingAddress } return setSourceGroup(fd, &sockOpts[ssoLeaveSourceGroup], ifi, grp, src) } // ExcludeSourceSpecificGroup excludes the source-specific group from // the already joined any-source groups by JoinGroup on the interface // ifi. func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP4(group) if grp == nil { return errMissingAddress } src := netAddrToIP4(source) if src == nil { return errMissingAddress } return setSourceGroup(fd, &sockOpts[ssoBlockSourceGroup], ifi, grp, src) } // IncludeSourceSpecificGroup includes the excluded source-specific // group by ExcludeSourceSpecificGroup again on the interface ifi. func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP4(group) if grp == nil { return errMissingAddress } src := netAddrToIP4(source) if src == nil { return errMissingAddress } return setSourceGroup(fd, &sockOpts[ssoUnblockSourceGroup], ifi, grp, src) } // ICMPFilter returns an ICMP filter. // Currently only Linux supports this. func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) { if !c.ok() { return nil, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return nil, err } return getICMPFilter(fd, &sockOpts[ssoICMPFilter]) } // SetICMPFilter deploys the ICMP filter. // Currently only Linux supports this. func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setICMPFilter(fd, &sockOpts[ssoICMPFilter], f) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/dgramopt_stub.go000066400000000000000000000072141264464372400245270ustar00rootroot00000000000000// Copyright 2012 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. // +build nacl plan9 solaris package ipv4 import "net" // MulticastTTL returns the time-to-live field value for outgoing // multicast packets. func (c *dgramOpt) MulticastTTL() (int, error) { return 0, errOpNoSupport } // SetMulticastTTL sets the time-to-live field value for future // outgoing multicast packets. func (c *dgramOpt) SetMulticastTTL(ttl int) error { return errOpNoSupport } // MulticastInterface returns the default interface for multicast // packet transmissions. func (c *dgramOpt) MulticastInterface() (*net.Interface, error) { return nil, errOpNoSupport } // SetMulticastInterface sets the default interface for future // multicast packet transmissions. func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error { return errOpNoSupport } // MulticastLoopback reports whether transmitted multicast packets // should be copied and send back to the originator. func (c *dgramOpt) MulticastLoopback() (bool, error) { return false, errOpNoSupport } // SetMulticastLoopback sets whether transmitted multicast packets // should be copied and send back to the originator. func (c *dgramOpt) SetMulticastLoopback(on bool) error { return errOpNoSupport } // JoinGroup joins the group address group on the interface ifi. // By default all sources that can cast data to group are accepted. // It's possible to mute and unmute data transmission from a specific // source by using ExcludeSourceSpecificGroup and // IncludeSourceSpecificGroup. // JoinGroup uses the system assigned multicast interface when ifi is // nil, although this is not recommended because the assignment // depends on platforms and sometimes it might require routing // configuration. func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error { return errOpNoSupport } // LeaveGroup leaves the group address group on the interface ifi // regardless of whether the group is any-source group or // source-specific group. func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error { return errOpNoSupport } // JoinSourceSpecificGroup joins the source-specific group comprising // group and source on the interface ifi. // JoinSourceSpecificGroup uses the system assigned multicast // interface when ifi is nil, although this is not recommended because // the assignment depends on platforms and sometimes it might require // routing configuration. func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { return errOpNoSupport } // LeaveSourceSpecificGroup leaves the source-specific group on the // interface ifi. func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { return errOpNoSupport } // ExcludeSourceSpecificGroup excludes the source-specific group from // the already joined any-source groups by JoinGroup on the interface // ifi. func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { return errOpNoSupport } // IncludeSourceSpecificGroup includes the excluded source-specific // group by ExcludeSourceSpecificGroup again on the interface ifi. func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { return errOpNoSupport } // ICMPFilter returns an ICMP filter. // Currently only Linux supports this. func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) { return nil, errOpNoSupport } // SetICMPFilter deploys the ICMP filter. // Currently only Linux supports this. func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error { return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/doc.go000066400000000000000000000173451264464372400224300ustar00rootroot00000000000000// Copyright 2012 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 ipv4 implements IP-level socket options for the Internet // Protocol version 4. // // The package provides IP-level socket options that allow // manipulation of IPv4 facilities. // // The IPv4 protocol and basic host requirements for IPv4 are defined // in RFC 791 and RFC 1122. // Host extensions for multicasting and socket interface extensions // for multicast source filters are defined in RFC 1112 and RFC 3678. // IGMPv1, IGMPv2 and IGMPv3 are defined in RFC 1112, RFC 2236 and RFC // 3376. // Source-specific multicast is defined in RFC 4607. // // // Unicasting // // The options for unicasting are available for net.TCPConn, // net.UDPConn and net.IPConn which are created as network connections // that use the IPv4 transport. When a single TCP connection carrying // a data flow of multiple packets needs to indicate the flow is // important, ipv4.Conn is used to set the type-of-service field on // the IPv4 header for each packet. // // ln, err := net.Listen("tcp4", "0.0.0.0:1024") // if err != nil { // // error handling // } // defer ln.Close() // for { // c, err := ln.Accept() // if err != nil { // // error handling // } // go func(c net.Conn) { // defer c.Close() // // The outgoing packets will be labeled DiffServ assured forwarding // class 1 low drop precedence, known as AF11 packets. // // if err := ipv4.NewConn(c).SetTOS(0x28); err != nil { // // error handling // } // if _, err := c.Write(data); err != nil { // // error handling // } // }(c) // } // // // Multicasting // // The options for multicasting are available for net.UDPConn and // net.IPconn which are created as network connections that use the // IPv4 transport. A few network facilities must be prepared before // you begin multicasting, at a minimum joining network interfaces and // multicast groups. // // en0, err := net.InterfaceByName("en0") // if err != nil { // // error handling // } // en1, err := net.InterfaceByIndex(911) // if err != nil { // // error handling // } // group := net.IPv4(224, 0, 0, 250) // // First, an application listens to an appropriate address with an // appropriate service port. // // c, err := net.ListenPacket("udp4", "0.0.0.0:1024") // if err != nil { // // error handling // } // defer c.Close() // // Second, the application joins multicast groups, starts listening to // the groups on the specified network interfaces. Note that the // service port for transport layer protocol does not matter with this // operation as joining groups affects only network and link layer // protocols, such as IPv4 and Ethernet. // // p := ipv4.NewPacketConn(c) // if err := p.JoinGroup(en0, &net.UDPAddr{IP: group}); err != nil { // // error handling // } // if err := p.JoinGroup(en1, &net.UDPAddr{IP: group}); err != nil { // // error handling // } // // The application might set per packet control message transmissions // between the protocol stack within the kernel. When the application // needs a destination address on an incoming packet, // SetControlMessage of ipv4.PacketConn is used to enable control // message transmissons. // // if err := p.SetControlMessage(ipv4.FlagDst, true); err != nil { // // error handling // } // // The application could identify whether the received packets are // of interest by using the control message that contains the // destination address of the received packet. // // b := make([]byte, 1500) // for { // n, cm, src, err := p.ReadFrom(b) // if err != nil { // // error handling // } // if cm.Dst.IsMulticast() { // if cm.Dst.Equal(group) { // // joined group, do something // } else { // // unknown group, discard // continue // } // } // // The application can also send both unicast and multicast packets. // // p.SetTOS(0x0) // p.SetTTL(16) // if _, err := p.WriteTo(data, nil, src); err != nil { // // error handling // } // dst := &net.UDPAddr{IP: group, Port: 1024} // for _, ifi := range []*net.Interface{en0, en1} { // if err := p.SetMulticastInterface(ifi); err != nil { // // error handling // } // p.SetMulticastTTL(2) // if _, err := p.WriteTo(data, nil, dst); err != nil { // // error handling // } // } // } // // // More multicasting // // An application that uses PacketConn or RawConn may join multiple // multicast groups. For example, a UDP listener with port 1024 might // join two different groups across over two different network // interfaces by using: // // c, err := net.ListenPacket("udp4", "0.0.0.0:1024") // if err != nil { // // error handling // } // defer c.Close() // p := ipv4.NewPacketConn(c) // if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil { // // error handling // } // if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}); err != nil { // // error handling // } // if err := p.JoinGroup(en1, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}); err != nil { // // error handling // } // // It is possible for multiple UDP listeners that listen on the same // UDP port to join the same multicast group. The net package will // provide a socket that listens to a wildcard address with reusable // UDP port when an appropriate multicast address prefix is passed to // the net.ListenPacket or net.ListenUDP. // // c1, err := net.ListenPacket("udp4", "224.0.0.0:1024") // if err != nil { // // error handling // } // defer c1.Close() // c2, err := net.ListenPacket("udp4", "224.0.0.0:1024") // if err != nil { // // error handling // } // defer c2.Close() // p1 := ipv4.NewPacketConn(c1) // if err := p1.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil { // // error handling // } // p2 := ipv4.NewPacketConn(c2) // if err := p2.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil { // // error handling // } // // Also it is possible for the application to leave or rejoin a // multicast group on the network interface. // // if err := p.LeaveGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil { // // error handling // } // if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 250)}); err != nil { // // error handling // } // // // Source-specific multicasting // // An application that uses PacketConn or RawConn on IGMPv3 supported // platform is able to join source-specific multicast groups. // The application may use JoinSourceSpecificGroup and // LeaveSourceSpecificGroup for the operation known as "include" mode, // // ssmgroup := net.UDPAddr{IP: net.IPv4(232, 7, 8, 9)} // ssmsource := net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)}) // if err := p.JoinSourceSpecificGroup(en0, &ssmgroup, &ssmsource); err != nil { // // error handling // } // if err := p.LeaveSourceSpecificGroup(en0, &ssmgroup, &ssmsource); err != nil { // // error handling // } // // or JoinGroup, ExcludeSourceSpecificGroup, // IncludeSourceSpecificGroup and LeaveGroup for the operation known // as "exclude" mode. // // exclsource := net.UDPAddr{IP: net.IPv4(192, 168, 0, 254)} // if err := p.JoinGroup(en0, &ssmgroup); err != nil { // // error handling // } // if err := p.ExcludeSourceSpecificGroup(en0, &ssmgroup, &exclsource); err != nil { // // error handling // } // if err := p.LeaveGroup(en0, &ssmgroup); err != nil { // // error handling // } // // Note that it depends on each platform implementation what happens // when an application which runs on IGMPv3 unsupported platform uses // JoinSourceSpecificGroup and LeaveSourceSpecificGroup. // In general the platform tries to fall back to conversations using // IGMPv1 or IGMPv2 and starts to listen to multicast traffic. // In the fallback case, ExcludeSourceSpecificGroup and // IncludeSourceSpecificGroup may return an error. package ipv4 // import "golang.org/x/net/ipv4" golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/endpoint.go000066400000000000000000000114521264464372400234740ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import ( "net" "syscall" "time" ) // A Conn represents a network endpoint that uses the IPv4 transport. // It is used to control basic IP-level socket options such as TOS and // TTL. type Conn struct { genericOpt } type genericOpt struct { net.Conn } func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil } // NewConn returns a new Conn. func NewConn(c net.Conn) *Conn { return &Conn{ genericOpt: genericOpt{Conn: c}, } } // A PacketConn represents a packet network endpoint that uses the // IPv4 transport. It is used to control several IP-level socket // options including multicasting. It also provides datagram based // network I/O methods specific to the IPv4 and higher layer protocols // such as UDP. type PacketConn struct { genericOpt dgramOpt payloadHandler } type dgramOpt struct { net.PacketConn } func (c *dgramOpt) ok() bool { return c != nil && c.PacketConn != nil } // SetControlMessage sets the per packet IP-level socket options. func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error { if !c.payloadHandler.ok() { return syscall.EINVAL } fd, err := c.payloadHandler.sysfd() if err != nil { return err } return setControlMessage(fd, &c.payloadHandler.rawOpt, cf, on) } // SetDeadline sets the read and write deadlines associated with the // endpoint. func (c *PacketConn) SetDeadline(t time.Time) error { if !c.payloadHandler.ok() { return syscall.EINVAL } return c.payloadHandler.PacketConn.SetDeadline(t) } // SetReadDeadline sets the read deadline associated with the // endpoint. func (c *PacketConn) SetReadDeadline(t time.Time) error { if !c.payloadHandler.ok() { return syscall.EINVAL } return c.payloadHandler.PacketConn.SetReadDeadline(t) } // SetWriteDeadline sets the write deadline associated with the // endpoint. func (c *PacketConn) SetWriteDeadline(t time.Time) error { if !c.payloadHandler.ok() { return syscall.EINVAL } return c.payloadHandler.PacketConn.SetWriteDeadline(t) } // Close closes the endpoint. func (c *PacketConn) Close() error { if !c.payloadHandler.ok() { return syscall.EINVAL } return c.payloadHandler.PacketConn.Close() } // NewPacketConn returns a new PacketConn using c as its underlying // transport. func NewPacketConn(c net.PacketConn) *PacketConn { p := &PacketConn{ genericOpt: genericOpt{Conn: c.(net.Conn)}, dgramOpt: dgramOpt{PacketConn: c}, payloadHandler: payloadHandler{PacketConn: c}, } if _, ok := c.(*net.IPConn); ok && sockOpts[ssoStripHeader].name > 0 { if fd, err := p.payloadHandler.sysfd(); err == nil { setInt(fd, &sockOpts[ssoStripHeader], boolint(true)) } } return p } // A RawConn represents a packet network endpoint that uses the IPv4 // transport. It is used to control several IP-level socket options // including IPv4 header manipulation. It also provides datagram // based network I/O methods specific to the IPv4 and higher layer // protocols that handle IPv4 datagram directly such as OSPF, GRE. type RawConn struct { genericOpt dgramOpt packetHandler } // SetControlMessage sets the per packet IP-level socket options. func (c *RawConn) SetControlMessage(cf ControlFlags, on bool) error { if !c.packetHandler.ok() { return syscall.EINVAL } fd, err := c.packetHandler.sysfd() if err != nil { return err } return setControlMessage(fd, &c.packetHandler.rawOpt, cf, on) } // SetDeadline sets the read and write deadlines associated with the // endpoint. func (c *RawConn) SetDeadline(t time.Time) error { if !c.packetHandler.ok() { return syscall.EINVAL } return c.packetHandler.c.SetDeadline(t) } // SetReadDeadline sets the read deadline associated with the // endpoint. func (c *RawConn) SetReadDeadline(t time.Time) error { if !c.packetHandler.ok() { return syscall.EINVAL } return c.packetHandler.c.SetReadDeadline(t) } // SetWriteDeadline sets the write deadline associated with the // endpoint. func (c *RawConn) SetWriteDeadline(t time.Time) error { if !c.packetHandler.ok() { return syscall.EINVAL } return c.packetHandler.c.SetWriteDeadline(t) } // Close closes the endpoint. func (c *RawConn) Close() error { if !c.packetHandler.ok() { return syscall.EINVAL } return c.packetHandler.c.Close() } // NewRawConn returns a new RawConn using c as its underlying // transport. func NewRawConn(c net.PacketConn) (*RawConn, error) { r := &RawConn{ genericOpt: genericOpt{Conn: c.(net.Conn)}, dgramOpt: dgramOpt{PacketConn: c}, packetHandler: packetHandler{c: c.(*net.IPConn)}, } fd, err := r.packetHandler.sysfd() if err != nil { return nil, err } if err := setInt(fd, &sockOpts[ssoHeaderPrepend], boolint(true)); err != nil { return nil, err } return r, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/example_test.go000066400000000000000000000123321264464372400243440ustar00rootroot00000000000000// Copyright 2012 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 ipv4_test import ( "fmt" "log" "net" "os" "runtime" "time" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" ) func ExampleConn_markingTCP() { ln, err := net.Listen("tcp", "0.0.0.0:1024") if err != nil { log.Fatal(err) } defer ln.Close() for { c, err := ln.Accept() if err != nil { log.Fatal(err) } go func(c net.Conn) { defer c.Close() if c.RemoteAddr().(*net.TCPAddr).IP.To4() != nil { p := ipv4.NewConn(c) if err := p.SetTOS(0x28); err != nil { // DSCP AF11 log.Fatal(err) } if err := p.SetTTL(128); err != nil { log.Fatal(err) } } if _, err := c.Write([]byte("HELLO-R-U-THERE-ACK")); err != nil { log.Fatal(err) } }(c) } } func ExamplePacketConn_servingOneShotMulticastDNS() { c, err := net.ListenPacket("udp4", "0.0.0.0:5353") // mDNS over UDP if err != nil { log.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c) en0, err := net.InterfaceByName("en0") if err != nil { log.Fatal(err) } mDNSLinkLocal := net.UDPAddr{IP: net.IPv4(224, 0, 0, 251)} if err := p.JoinGroup(en0, &mDNSLinkLocal); err != nil { log.Fatal(err) } defer p.LeaveGroup(en0, &mDNSLinkLocal) if err := p.SetControlMessage(ipv4.FlagDst, true); err != nil { log.Fatal(err) } b := make([]byte, 1500) for { _, cm, peer, err := p.ReadFrom(b) if err != nil { log.Fatal(err) } if !cm.Dst.IsMulticast() || !cm.Dst.Equal(mDNSLinkLocal.IP) { continue } answers := []byte("FAKE-MDNS-ANSWERS") // fake mDNS answers, you need to implement this if _, err := p.WriteTo(answers, nil, peer); err != nil { log.Fatal(err) } } } func ExamplePacketConn_tracingIPPacketRoute() { // Tracing an IP packet route to www.google.com. const host = "www.google.com" ips, err := net.LookupIP(host) if err != nil { log.Fatal(err) } var dst net.IPAddr for _, ip := range ips { if ip.To4() != nil { dst.IP = ip fmt.Printf("using %v for tracing an IP packet route to %s\n", dst.IP, host) break } } if dst.IP == nil { log.Fatal("no A record found") } c, err := net.ListenPacket("ip4:1", "0.0.0.0") // ICMP for IPv4 if err != nil { log.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c) if err := p.SetControlMessage(ipv4.FlagTTL|ipv4.FlagSrc|ipv4.FlagDst|ipv4.FlagInterface, true); err != nil { log.Fatal(err) } wm := icmp.Message{ Type: ipv4.ICMPTypeEcho, Code: 0, Body: &icmp.Echo{ ID: os.Getpid() & 0xffff, Data: []byte("HELLO-R-U-THERE"), }, } rb := make([]byte, 1500) for i := 1; i <= 64; i++ { // up to 64 hops wm.Body.(*icmp.Echo).Seq = i wb, err := wm.Marshal(nil) if err != nil { log.Fatal(err) } if err := p.SetTTL(i); err != nil { log.Fatal(err) } // In the real world usually there are several // multiple traffic-engineered paths for each hop. // You may need to probe a few times to each hop. begin := time.Now() if _, err := p.WriteTo(wb, nil, &dst); err != nil { log.Fatal(err) } if err := p.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil { log.Fatal(err) } n, cm, peer, err := p.ReadFrom(rb) if err != nil { if err, ok := err.(net.Error); ok && err.Timeout() { fmt.Printf("%v\t*\n", i) continue } log.Fatal(err) } rm, err := icmp.ParseMessage(1, rb[:n]) if err != nil { log.Fatal(err) } rtt := time.Since(begin) // In the real world you need to determine whether the // received message is yours using ControlMessage.Src, // ControlMessage.Dst, icmp.Echo.ID and icmp.Echo.Seq. switch rm.Type { case ipv4.ICMPTypeTimeExceeded: names, _ := net.LookupAddr(peer.String()) fmt.Printf("%d\t%v %+v %v\n\t%+v\n", i, peer, names, rtt, cm) case ipv4.ICMPTypeEchoReply: names, _ := net.LookupAddr(peer.String()) fmt.Printf("%d\t%v %+v %v\n\t%+v\n", i, peer, names, rtt, cm) return default: log.Printf("unknown ICMP message: %+v\n", rm) } } } func ExampleRawConn_advertisingOSPFHello() { c, err := net.ListenPacket("ip4:89", "0.0.0.0") // OSPF for IPv4 if err != nil { log.Fatal(err) } defer c.Close() r, err := ipv4.NewRawConn(c) if err != nil { log.Fatal(err) } en0, err := net.InterfaceByName("en0") if err != nil { log.Fatal(err) } allSPFRouters := net.IPAddr{IP: net.IPv4(224, 0, 0, 5)} if err := r.JoinGroup(en0, &allSPFRouters); err != nil { log.Fatal(err) } defer r.LeaveGroup(en0, &allSPFRouters) hello := make([]byte, 24) // fake hello data, you need to implement this ospf := make([]byte, 24) // fake ospf header, you need to implement this ospf[0] = 2 // version 2 ospf[1] = 1 // hello packet ospf = append(ospf, hello...) iph := &ipv4.Header{ Version: ipv4.Version, Len: ipv4.HeaderLen, TOS: 0xc0, // DSCP CS6 TotalLen: ipv4.HeaderLen + len(ospf), TTL: 1, Protocol: 89, Dst: allSPFRouters.IP.To4(), } var cm *ipv4.ControlMessage switch runtime.GOOS { case "darwin", "linux": cm = &ipv4.ControlMessage{IfIndex: en0.Index} default: if err := r.SetMulticastInterface(en0); err != nil { log.Fatal(err) } } if err := r.WriteTo(iph, ospf, cm); err != nil { log.Fatal(err) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/gen.go000066400000000000000000000117321264464372400224260ustar00rootroot00000000000000// Copyright 2013 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. // +build ignore //go:generate go run gen.go // This program generates system adaptation constants and types, // internet protocol constants and tables by reading template files // and IANA protocol registries. package main import ( "bytes" "encoding/xml" "fmt" "go/format" "io" "io/ioutil" "net/http" "os" "os/exec" "runtime" "strconv" "strings" ) func main() { if err := genzsys(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } if err := geniana(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func genzsys() error { defs := "defs_" + runtime.GOOS + ".go" f, err := os.Open(defs) if err != nil { if os.IsNotExist(err) { return nil } return err } f.Close() cmd := exec.Command("go", "tool", "cgo", "-godefs", defs) b, err := cmd.Output() if err != nil { return err } // The ipv4 pacakge still supports go1.2, and so we need to // take care of additional platforms in go1.3 and above for // working with go1.2. switch { case runtime.GOOS == "dragonfly" || runtime.GOOS == "solaris": b = bytes.Replace(b, []byte("package ipv4\n"), []byte("// +build "+runtime.GOOS+"\n\npackage ipv4\n"), 1) case runtime.GOOS == "linux" && (runtime.GOARCH == "arm64" || runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le"): b = bytes.Replace(b, []byte("package ipv4\n"), []byte("// +build "+runtime.GOOS+","+runtime.GOARCH+"\n\npackage ipv4\n"), 1) } b, err = format.Source(b) if err != nil { return err } zsys := "zsys_" + runtime.GOOS + ".go" switch runtime.GOOS { case "freebsd", "linux": zsys = "zsys_" + runtime.GOOS + "_" + runtime.GOARCH + ".go" } if err := ioutil.WriteFile(zsys, b, 0644); err != nil { return err } return nil } var registries = []struct { url string parse func(io.Writer, io.Reader) error }{ { "http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml", parseICMPv4Parameters, }, } func geniana() error { var bb bytes.Buffer fmt.Fprintf(&bb, "// go generate gen.go\n") fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n") fmt.Fprintf(&bb, "package ipv4\n\n") for _, r := range registries { resp, err := http.Get(r.url) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("got HTTP status code %v for %v\n", resp.StatusCode, r.url) } if err := r.parse(&bb, resp.Body); err != nil { return err } fmt.Fprintf(&bb, "\n") } b, err := format.Source(bb.Bytes()) if err != nil { return err } if err := ioutil.WriteFile("iana.go", b, 0644); err != nil { return err } return nil } func parseICMPv4Parameters(w io.Writer, r io.Reader) error { dec := xml.NewDecoder(r) var icp icmpv4Parameters if err := dec.Decode(&icp); err != nil { return err } prs := icp.escape() fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated) fmt.Fprintf(w, "const (\n") for _, pr := range prs { if pr.Descr == "" { continue } fmt.Fprintf(w, "ICMPType%s ICMPType = %d", pr.Descr, pr.Value) fmt.Fprintf(w, "// %s\n", pr.OrigDescr) } fmt.Fprintf(w, ")\n\n") fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated) fmt.Fprintf(w, "var icmpTypes = map[ICMPType]string{\n") for _, pr := range prs { if pr.Descr == "" { continue } fmt.Fprintf(w, "%d: %q,\n", pr.Value, strings.ToLower(pr.OrigDescr)) } fmt.Fprintf(w, "}\n") return nil } type icmpv4Parameters struct { XMLName xml.Name `xml:"registry"` Title string `xml:"title"` Updated string `xml:"updated"` Registries []struct { Title string `xml:"title"` Records []struct { Value string `xml:"value"` Descr string `xml:"description"` } `xml:"record"` } `xml:"registry"` } type canonICMPv4ParamRecord struct { OrigDescr string Descr string Value int } func (icp *icmpv4Parameters) escape() []canonICMPv4ParamRecord { id := -1 for i, r := range icp.Registries { if strings.Contains(r.Title, "Type") || strings.Contains(r.Title, "type") { id = i break } } if id < 0 { return nil } prs := make([]canonICMPv4ParamRecord, len(icp.Registries[id].Records)) sr := strings.NewReplacer( "Messages", "", "Message", "", "ICMP", "", "+", "P", "-", "", "/", "", ".", "", " ", "", ) for i, pr := range icp.Registries[id].Records { if strings.Contains(pr.Descr, "Reserved") || strings.Contains(pr.Descr, "Unassigned") || strings.Contains(pr.Descr, "Deprecated") || strings.Contains(pr.Descr, "Experiment") || strings.Contains(pr.Descr, "experiment") { continue } ss := strings.Split(pr.Descr, "\n") if len(ss) > 1 { prs[i].Descr = strings.Join(ss, " ") } else { prs[i].Descr = ss[0] } s := strings.TrimSpace(prs[i].Descr) prs[i].OrigDescr = s prs[i].Descr = sr.Replace(s) prs[i].Value, _ = strconv.Atoi(pr.Value) } return prs } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/genericopt_posix.go000066400000000000000000000024131264464372400252320ustar00rootroot00000000000000// Copyright 2012 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. // +build darwin dragonfly freebsd linux netbsd openbsd windows package ipv4 import "syscall" // TOS returns the type-of-service field value for outgoing packets. func (c *genericOpt) TOS() (int, error) { if !c.ok() { return 0, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return 0, err } return getInt(fd, &sockOpts[ssoTOS]) } // SetTOS sets the type-of-service field value for future outgoing // packets. func (c *genericOpt) SetTOS(tos int) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setInt(fd, &sockOpts[ssoTOS], tos) } // TTL returns the time-to-live field value for outgoing packets. func (c *genericOpt) TTL() (int, error) { if !c.ok() { return 0, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return 0, err } return getInt(fd, &sockOpts[ssoTTL]) } // SetTTL sets the time-to-live field value for future outgoing // packets. func (c *genericOpt) SetTTL(ttl int) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setInt(fd, &sockOpts[ssoTTL], ttl) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/genericopt_stub.go000066400000000000000000000014121264464372400250430ustar00rootroot00000000000000// Copyright 2012 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. // +build nacl plan9 solaris package ipv4 // TOS returns the type-of-service field value for outgoing packets. func (c *genericOpt) TOS() (int, error) { return 0, errOpNoSupport } // SetTOS sets the type-of-service field value for future outgoing // packets. func (c *genericOpt) SetTOS(tos int) error { return errOpNoSupport } // TTL returns the time-to-live field value for outgoing packets. func (c *genericOpt) TTL() (int, error) { return 0, errOpNoSupport } // SetTTL sets the time-to-live field value for future outgoing // packets. func (c *genericOpt) SetTTL(ttl int) error { return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/header.go000066400000000000000000000102721264464372400231030ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import ( "fmt" "net" "runtime" "syscall" "unsafe" ) const ( Version = 4 // protocol version HeaderLen = 20 // header length without extension headers maxHeaderLen = 60 // sensible default, revisit if later RFCs define new usage of version and header length fields ) type HeaderFlags int const ( MoreFragments HeaderFlags = 1 << iota // more fragments flag DontFragment // don't fragment flag ) // A Header represents an IPv4 header. type Header struct { Version int // protocol version Len int // header length TOS int // type-of-service TotalLen int // packet total length ID int // identification Flags HeaderFlags // flags FragOff int // fragment offset TTL int // time-to-live Protocol int // next protocol Checksum int // checksum Src net.IP // source address Dst net.IP // destination address Options []byte // options, extension headers } func (h *Header) String() string { if h == nil { return "" } return fmt.Sprintf("ver=%d hdrlen=%d tos=%#x totallen=%d id=%#x flags=%#x fragoff=%#x ttl=%d proto=%d cksum=%#x src=%v dst=%v", h.Version, h.Len, h.TOS, h.TotalLen, h.ID, h.Flags, h.FragOff, h.TTL, h.Protocol, h.Checksum, h.Src, h.Dst) } // Marshal returns the binary encoding of the IPv4 header h. func (h *Header) Marshal() ([]byte, error) { if h == nil { return nil, syscall.EINVAL } if h.Len < HeaderLen { return nil, errHeaderTooShort } hdrlen := HeaderLen + len(h.Options) b := make([]byte, hdrlen) b[0] = byte(Version<<4 | (hdrlen >> 2 & 0x0f)) b[1] = byte(h.TOS) flagsAndFragOff := (h.FragOff & 0x1fff) | int(h.Flags<<13) switch runtime.GOOS { case "darwin", "dragonfly", "freebsd", "netbsd": // TODO(mikio): fix potential misaligned memory access *(*uint16)(unsafe.Pointer(&b[2:3][0])) = uint16(h.TotalLen) *(*uint16)(unsafe.Pointer(&b[6:7][0])) = uint16(flagsAndFragOff) default: b[2], b[3] = byte(h.TotalLen>>8), byte(h.TotalLen) b[6], b[7] = byte(flagsAndFragOff>>8), byte(flagsAndFragOff) } b[4], b[5] = byte(h.ID>>8), byte(h.ID) b[8] = byte(h.TTL) b[9] = byte(h.Protocol) b[10], b[11] = byte(h.Checksum>>8), byte(h.Checksum) if ip := h.Src.To4(); ip != nil { copy(b[12:16], ip[:net.IPv4len]) } if ip := h.Dst.To4(); ip != nil { copy(b[16:20], ip[:net.IPv4len]) } else { return nil, errMissingAddress } if len(h.Options) > 0 { copy(b[HeaderLen:], h.Options) } return b, nil } // See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html. var freebsdVersion uint32 // ParseHeader parses b as an IPv4 header. func ParseHeader(b []byte) (*Header, error) { if len(b) < HeaderLen { return nil, errHeaderTooShort } hdrlen := int(b[0]&0x0f) << 2 if hdrlen > len(b) { return nil, errBufferTooShort } h := &Header{ Version: int(b[0] >> 4), Len: hdrlen, TOS: int(b[1]), ID: int(b[4])<<8 | int(b[5]), TTL: int(b[8]), Protocol: int(b[9]), Checksum: int(b[10])<<8 | int(b[11]), Src: net.IPv4(b[12], b[13], b[14], b[15]), Dst: net.IPv4(b[16], b[17], b[18], b[19]), } switch runtime.GOOS { case "darwin", "dragonfly", "netbsd": // TODO(mikio): fix potential misaligned memory access h.TotalLen = int(*(*uint16)(unsafe.Pointer(&b[2:3][0]))) + hdrlen // TODO(mikio): fix potential misaligned memory access h.FragOff = int(*(*uint16)(unsafe.Pointer(&b[6:7][0]))) case "freebsd": // TODO(mikio): fix potential misaligned memory access h.TotalLen = int(*(*uint16)(unsafe.Pointer(&b[2:3][0]))) if freebsdVersion < 1000000 { h.TotalLen += hdrlen } // TODO(mikio): fix potential misaligned memory access h.FragOff = int(*(*uint16)(unsafe.Pointer(&b[6:7][0]))) default: h.TotalLen = int(b[2])<<8 | int(b[3]) h.FragOff = int(b[6])<<8 | int(b[7]) } h.Flags = HeaderFlags(h.FragOff&0xe000) >> 13 h.FragOff = h.FragOff & 0x1fff if hdrlen-HeaderLen > 0 { h.Options = make([]byte, hdrlen-HeaderLen) copy(h.Options, b[HeaderLen:]) } return h, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/header_test.go000066400000000000000000000047651264464372400241540ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import ( "bytes" "net" "reflect" "runtime" "strings" "testing" ) var ( wireHeaderFromKernel = [HeaderLen]byte{ 0x45, 0x01, 0xbe, 0xef, 0xca, 0xfe, 0x45, 0xdc, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, } wireHeaderToKernel = [HeaderLen]byte{ 0x45, 0x01, 0xbe, 0xef, 0xca, 0xfe, 0x45, 0xdc, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, } wireHeaderFromTradBSDKernel = [HeaderLen]byte{ 0x45, 0x01, 0xdb, 0xbe, 0xca, 0xfe, 0xdc, 0x45, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, } wireHeaderFromFreeBSD10Kernel = [HeaderLen]byte{ 0x45, 0x01, 0xef, 0xbe, 0xca, 0xfe, 0xdc, 0x45, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, } wireHeaderToTradBSDKernel = [HeaderLen]byte{ 0x45, 0x01, 0xef, 0xbe, 0xca, 0xfe, 0xdc, 0x45, 0xff, 0x01, 0xde, 0xad, 172, 16, 254, 254, 192, 168, 0, 1, } // TODO(mikio): Add platform dependent wire header formats when // we support new platforms. testHeader = &Header{ Version: Version, Len: HeaderLen, TOS: 1, TotalLen: 0xbeef, ID: 0xcafe, Flags: DontFragment, FragOff: 1500, TTL: 255, Protocol: 1, Checksum: 0xdead, Src: net.IPv4(172, 16, 254, 254), Dst: net.IPv4(192, 168, 0, 1), } ) func TestMarshalHeader(t *testing.T) { b, err := testHeader.Marshal() if err != nil { t.Fatal(err) } var wh []byte switch runtime.GOOS { case "darwin", "dragonfly", "netbsd": wh = wireHeaderToTradBSDKernel[:] case "freebsd": if freebsdVersion < 1000000 { wh = wireHeaderToTradBSDKernel[:] } else { wh = wireHeaderFromFreeBSD10Kernel[:] } default: wh = wireHeaderToKernel[:] } if !bytes.Equal(b, wh) { t.Fatalf("got %#v; want %#v", b, wh) } } func TestParseHeader(t *testing.T) { var wh []byte switch runtime.GOOS { case "darwin", "dragonfly", "netbsd": wh = wireHeaderFromTradBSDKernel[:] case "freebsd": if freebsdVersion < 1000000 { wh = wireHeaderFromTradBSDKernel[:] } else { wh = wireHeaderFromFreeBSD10Kernel[:] } default: wh = wireHeaderFromKernel[:] } h, err := ParseHeader(wh) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(h, testHeader) { t.Fatalf("got %#v; want %#v", h, testHeader) } s := h.String() if strings.Contains(s, ",") { t.Fatalf("should be space-separated values: %s", s) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/helper.go000066400000000000000000000017631264464372400231370ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import ( "errors" "net" ) var ( errMissingAddress = errors.New("missing address") errMissingHeader = errors.New("missing header") errHeaderTooShort = errors.New("header too short") errBufferTooShort = errors.New("buffer too short") errInvalidConnType = errors.New("invalid conn type") errOpNoSupport = errors.New("operation not supported") errNoSuchInterface = errors.New("no such interface") errNoSuchMulticastInterface = errors.New("no such multicast interface") ) func boolint(b bool) int { if b { return 1 } return 0 } func netAddrToIP4(a net.Addr) net.IP { switch v := a.(type) { case *net.UDPAddr: if ip := v.IP.To4(); ip != nil { return ip } case *net.IPAddr: if ip := v.IP.To4(); ip != nil { return ip } } return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/helper_stub.go000066400000000000000000000007651264464372400241750ustar00rootroot00000000000000// Copyright 2012 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. // +build nacl plan9 solaris package ipv4 func (c *genericOpt) sysfd() (int, error) { return 0, errOpNoSupport } func (c *dgramOpt) sysfd() (int, error) { return 0, errOpNoSupport } func (c *payloadHandler) sysfd() (int, error) { return 0, errOpNoSupport } func (c *packetHandler) sysfd() (int, error) { return 0, errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/helper_unix.go000066400000000000000000000021261264464372400241740ustar00rootroot00000000000000// Copyright 2012 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. // +build darwin dragonfly freebsd linux netbsd openbsd package ipv4 import ( "net" "reflect" ) func (c *genericOpt) sysfd() (int, error) { switch p := c.Conn.(type) { case *net.TCPConn, *net.UDPConn, *net.IPConn: return sysfd(p) } return 0, errInvalidConnType } func (c *dgramOpt) sysfd() (int, error) { switch p := c.PacketConn.(type) { case *net.UDPConn, *net.IPConn: return sysfd(p.(net.Conn)) } return 0, errInvalidConnType } func (c *payloadHandler) sysfd() (int, error) { return sysfd(c.PacketConn.(net.Conn)) } func (c *packetHandler) sysfd() (int, error) { return sysfd(c.c) } func sysfd(c net.Conn) (int, error) { cv := reflect.ValueOf(c) switch ce := cv.Elem(); ce.Kind() { case reflect.Struct: netfd := ce.FieldByName("conn").FieldByName("fd") switch fe := netfd.Elem(); fe.Kind() { case reflect.Struct: fd := fe.FieldByName("sysfd") return int(fd.Int()), nil } } return 0, errInvalidConnType } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/helper_windows.go000066400000000000000000000022471264464372400247070ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import ( "net" "reflect" "syscall" ) func (c *genericOpt) sysfd() (syscall.Handle, error) { switch p := c.Conn.(type) { case *net.TCPConn, *net.UDPConn, *net.IPConn: return sysfd(p) } return syscall.InvalidHandle, errInvalidConnType } func (c *dgramOpt) sysfd() (syscall.Handle, error) { switch p := c.PacketConn.(type) { case *net.UDPConn, *net.IPConn: return sysfd(p.(net.Conn)) } return syscall.InvalidHandle, errInvalidConnType } func (c *payloadHandler) sysfd() (syscall.Handle, error) { return sysfd(c.PacketConn.(net.Conn)) } func (c *packetHandler) sysfd() (syscall.Handle, error) { return sysfd(c.c) } func sysfd(c net.Conn) (syscall.Handle, error) { cv := reflect.ValueOf(c) switch ce := cv.Elem(); ce.Kind() { case reflect.Struct: netfd := ce.FieldByName("conn").FieldByName("fd") switch fe := netfd.Elem(); fe.Kind() { case reflect.Struct: fd := fe.FieldByName("sysfd") return syscall.Handle(fd.Uint()), nil } } return syscall.InvalidHandle, errInvalidConnType } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/iana.go000066400000000000000000000023131264464372400225600ustar00rootroot00000000000000// go generate gen.go // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT package ipv4 // Internet Control Message Protocol (ICMP) Parameters, Updated: 2013-04-19 const ( ICMPTypeEchoReply ICMPType = 0 // Echo Reply ICMPTypeDestinationUnreachable ICMPType = 3 // Destination Unreachable ICMPTypeRedirect ICMPType = 5 // Redirect ICMPTypeEcho ICMPType = 8 // Echo ICMPTypeRouterAdvertisement ICMPType = 9 // Router Advertisement ICMPTypeRouterSolicitation ICMPType = 10 // Router Solicitation ICMPTypeTimeExceeded ICMPType = 11 // Time Exceeded ICMPTypeParameterProblem ICMPType = 12 // Parameter Problem ICMPTypeTimestamp ICMPType = 13 // Timestamp ICMPTypeTimestampReply ICMPType = 14 // Timestamp Reply ICMPTypePhoturis ICMPType = 40 // Photuris ) // Internet Control Message Protocol (ICMP) Parameters, Updated: 2013-04-19 var icmpTypes = map[ICMPType]string{ 0: "echo reply", 3: "destination unreachable", 5: "redirect", 8: "echo", 9: "router advertisement", 10: "router solicitation", 11: "time exceeded", 12: "parameter problem", 13: "timestamp", 14: "timestamp reply", 40: "photuris", } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/icmp.go000066400000000000000000000030231264464372400225770ustar00rootroot00000000000000// Copyright 2013 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 ipv4 import "golang.org/x/net/internal/iana" // An ICMPType represents a type of ICMP message. type ICMPType int func (typ ICMPType) String() string { s, ok := icmpTypes[typ] if !ok { return "" } return s } // Protocol returns the ICMPv4 protocol number. func (typ ICMPType) Protocol() int { return iana.ProtocolICMP } // An ICMPFilter represents an ICMP message filter for incoming // packets. The filter belongs to a packet delivery path on a host and // it cannot interact with forwarding packets or tunnel-outer packets. // // Note: RFC 2460 defines a reasonable role model and it works not // only for IPv6 but IPv4. A node means a device that implements IP. // A router means a node that forwards IP packets not explicitly // addressed to itself, and a host means a node that is not a router. type ICMPFilter struct { sysICMPFilter } // Accept accepts incoming ICMP packets including the type field value // typ. func (f *ICMPFilter) Accept(typ ICMPType) { f.accept(typ) } // Block blocks incoming ICMP packets including the type field value // typ. func (f *ICMPFilter) Block(typ ICMPType) { f.block(typ) } // SetAll sets the filter action to the filter. func (f *ICMPFilter) SetAll(block bool) { f.setAll(block) } // WillBlock reports whether the ICMP type will be blocked. func (f *ICMPFilter) WillBlock(typ ICMPType) bool { return f.willBlock(typ) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/icmp_linux.go000066400000000000000000000010461264464372400240210ustar00rootroot00000000000000// Copyright 2014 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 ipv4 func (f *sysICMPFilter) accept(typ ICMPType) { f.Data &^= 1 << (uint32(typ) & 31) } func (f *sysICMPFilter) block(typ ICMPType) { f.Data |= 1 << (uint32(typ) & 31) } func (f *sysICMPFilter) setAll(block bool) { if block { f.Data = 1<<32 - 1 } else { f.Data = 0 } } func (f *sysICMPFilter) willBlock(typ ICMPType) bool { return f.Data&(1<<(uint32(typ)&31)) != 0 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/icmp_stub.go000066400000000000000000000007321264464372400236400ustar00rootroot00000000000000// Copyright 2014 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. // +build !linux package ipv4 const sysSizeofICMPFilter = 0x0 type sysICMPFilter struct { } func (f *sysICMPFilter) accept(typ ICMPType) { } func (f *sysICMPFilter) block(typ ICMPType) { } func (f *sysICMPFilter) setAll(block bool) { } func (f *sysICMPFilter) willBlock(typ ICMPType) bool { return false } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/icmp_test.go000066400000000000000000000035261264464372400236460ustar00rootroot00000000000000// Copyright 2014 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 ipv4_test import ( "net" "reflect" "runtime" "testing" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv4" ) var icmpStringTests = []struct { in ipv4.ICMPType out string }{ {ipv4.ICMPTypeDestinationUnreachable, "destination unreachable"}, {256, ""}, } func TestICMPString(t *testing.T) { for _, tt := range icmpStringTests { s := tt.in.String() if s != tt.out { t.Errorf("got %s; want %s", s, tt.out) } } } func TestICMPFilter(t *testing.T) { switch runtime.GOOS { case "linux": default: t.Skipf("not supported on %s", runtime.GOOS) } var f ipv4.ICMPFilter for _, toggle := range []bool{false, true} { f.SetAll(toggle) for _, typ := range []ipv4.ICMPType{ ipv4.ICMPTypeDestinationUnreachable, ipv4.ICMPTypeEchoReply, ipv4.ICMPTypeTimeExceeded, ipv4.ICMPTypeParameterProblem, } { f.Accept(typ) if f.WillBlock(typ) { t.Errorf("ipv4.ICMPFilter.Set(%v, false) failed", typ) } f.Block(typ) if !f.WillBlock(typ) { t.Errorf("ipv4.ICMPFilter.Set(%v, true) failed", typ) } } } } func TestSetICMPFilter(t *testing.T) { switch runtime.GOOS { case "linux": default: t.Skipf("not supported on %s", runtime.GOOS) } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } c, err := net.ListenPacket("ip4:icmp", "127.0.0.1") if err != nil { t.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c) var f ipv4.ICMPFilter f.SetAll(true) f.Accept(ipv4.ICMPTypeEcho) f.Accept(ipv4.ICMPTypeEchoReply) if err := p.SetICMPFilter(&f); err != nil { t.Fatal(err) } kf, err := p.ICMPFilter() if err != nil { t.Fatal(err) } if !reflect.DeepEqual(kf, &f) { t.Fatalf("got %#v; want %#v", kf, f) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/mocktransponder_test.go000066400000000000000000000006051264464372400261220ustar00rootroot00000000000000// Copyright 2012 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 ipv4_test import ( "net" "testing" ) func acceptor(t *testing.T, ln net.Listener, done chan<- bool) { defer func() { done <- true }() c, err := ln.Accept() if err != nil { t.Error(err) return } c.Close() } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/multicast_test.go000066400000000000000000000215431264464372400247220ustar00rootroot00000000000000// Copyright 2012 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 ipv4_test import ( "bytes" "net" "os" "runtime" "testing" "time" "golang.org/x/net/icmp" "golang.org/x/net/internal/iana" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv4" ) var packetConnReadWriteMulticastUDPTests = []struct { addr string grp, src *net.UDPAddr }{ {"224.0.0.0:0", &net.UDPAddr{IP: net.IPv4(224, 0, 0, 254)}, nil}, // see RFC 4727 {"232.0.1.0:0", &net.UDPAddr{IP: net.IPv4(232, 0, 1, 254)}, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771 } func TestPacketConnReadWriteMulticastUDP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } for _, tt := range packetConnReadWriteMulticastUDPTests { c, err := net.ListenPacket("udp4", tt.addr) if err != nil { t.Fatal(err) } defer c.Close() grp := *tt.grp grp.Port = c.LocalAddr().(*net.UDPAddr).Port p := ipv4.NewPacketConn(c) defer p.Close() if tt.src == nil { if err := p.JoinGroup(ifi, &grp); err != nil { t.Fatal(err) } defer p.LeaveGroup(ifi, &grp) } else { if err := p.JoinSourceSpecificGroup(ifi, &grp, tt.src); err != nil { switch runtime.GOOS { case "freebsd", "linux": default: // platforms that don't support IGMPv2/3 fail here t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } defer p.LeaveSourceSpecificGroup(ifi, &grp, tt.src) } if err := p.SetMulticastInterface(ifi); err != nil { t.Fatal(err) } if _, err := p.MulticastInterface(); err != nil { t.Fatal(err) } if err := p.SetMulticastLoopback(true); err != nil { t.Fatal(err) } if _, err := p.MulticastLoopback(); err != nil { t.Fatal(err) } cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface wb := []byte("HELLO-R-U-THERE") for i, toggle := range []bool{true, false, true} { if err := p.SetControlMessage(cf, toggle); err != nil { if nettest.ProtocolNotSupported(err) { t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil { t.Fatal(err) } p.SetMulticastTTL(i + 1) if n, err := p.WriteTo(wb, nil, &grp); err != nil { t.Fatal(err) } else if n != len(wb) { t.Fatalf("got %v; want %v", n, len(wb)) } rb := make([]byte, 128) if n, _, _, err := p.ReadFrom(rb); err != nil { t.Fatal(err) } else if !bytes.Equal(rb[:n], wb) { t.Fatalf("got %v; want %v", rb[:n], wb) } } } } var packetConnReadWriteMulticastICMPTests = []struct { grp, src *net.IPAddr }{ {&net.IPAddr{IP: net.IPv4(224, 0, 0, 254)}, nil}, // see RFC 4727 {&net.IPAddr{IP: net.IPv4(232, 0, 1, 254)}, &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771 } func TestPacketConnReadWriteMulticastICMP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } for _, tt := range packetConnReadWriteMulticastICMPTests { c, err := net.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { t.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c) defer p.Close() if tt.src == nil { if err := p.JoinGroup(ifi, tt.grp); err != nil { t.Fatal(err) } defer p.LeaveGroup(ifi, tt.grp) } else { if err := p.JoinSourceSpecificGroup(ifi, tt.grp, tt.src); err != nil { switch runtime.GOOS { case "freebsd", "linux": default: // platforms that don't support IGMPv2/3 fail here t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } defer p.LeaveSourceSpecificGroup(ifi, tt.grp, tt.src) } if err := p.SetMulticastInterface(ifi); err != nil { t.Fatal(err) } if _, err := p.MulticastInterface(); err != nil { t.Fatal(err) } if err := p.SetMulticastLoopback(true); err != nil { t.Fatal(err) } if _, err := p.MulticastLoopback(); err != nil { t.Fatal(err) } cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface for i, toggle := range []bool{true, false, true} { wb, err := (&icmp.Message{ Type: ipv4.ICMPTypeEcho, Code: 0, Body: &icmp.Echo{ ID: os.Getpid() & 0xffff, Seq: i + 1, Data: []byte("HELLO-R-U-THERE"), }, }).Marshal(nil) if err != nil { t.Fatal(err) } if err := p.SetControlMessage(cf, toggle); err != nil { if nettest.ProtocolNotSupported(err) { t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil { t.Fatal(err) } p.SetMulticastTTL(i + 1) if n, err := p.WriteTo(wb, nil, tt.grp); err != nil { t.Fatal(err) } else if n != len(wb) { t.Fatalf("got %v; want %v", n, len(wb)) } rb := make([]byte, 128) if n, _, _, err := p.ReadFrom(rb); err != nil { t.Fatal(err) } else { m, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n]) if err != nil { t.Fatal(err) } switch { case m.Type == ipv4.ICMPTypeEchoReply && m.Code == 0: // net.inet.icmp.bmcastecho=1 case m.Type == ipv4.ICMPTypeEcho && m.Code == 0: // net.inet.icmp.bmcastecho=0 default: t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0) } } } } } var rawConnReadWriteMulticastICMPTests = []struct { grp, src *net.IPAddr }{ {&net.IPAddr{IP: net.IPv4(224, 0, 0, 254)}, nil}, // see RFC 4727 {&net.IPAddr{IP: net.IPv4(232, 0, 1, 254)}, &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771 } func TestRawConnReadWriteMulticastICMP(t *testing.T) { if testing.Short() { t.Skip("to avoid external network") } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } for _, tt := range rawConnReadWriteMulticastICMPTests { c, err := net.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { t.Fatal(err) } defer c.Close() r, err := ipv4.NewRawConn(c) if err != nil { t.Fatal(err) } defer r.Close() if tt.src == nil { if err := r.JoinGroup(ifi, tt.grp); err != nil { t.Fatal(err) } defer r.LeaveGroup(ifi, tt.grp) } else { if err := r.JoinSourceSpecificGroup(ifi, tt.grp, tt.src); err != nil { switch runtime.GOOS { case "freebsd", "linux": default: // platforms that don't support IGMPv2/3 fail here t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } defer r.LeaveSourceSpecificGroup(ifi, tt.grp, tt.src) } if err := r.SetMulticastInterface(ifi); err != nil { t.Fatal(err) } if _, err := r.MulticastInterface(); err != nil { t.Fatal(err) } if err := r.SetMulticastLoopback(true); err != nil { t.Fatal(err) } if _, err := r.MulticastLoopback(); err != nil { t.Fatal(err) } cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface for i, toggle := range []bool{true, false, true} { wb, err := (&icmp.Message{ Type: ipv4.ICMPTypeEcho, Code: 0, Body: &icmp.Echo{ ID: os.Getpid() & 0xffff, Seq: i + 1, Data: []byte("HELLO-R-U-THERE"), }, }).Marshal(nil) if err != nil { t.Fatal(err) } wh := &ipv4.Header{ Version: ipv4.Version, Len: ipv4.HeaderLen, TOS: i + 1, TotalLen: ipv4.HeaderLen + len(wb), Protocol: 1, Dst: tt.grp.IP, } if err := r.SetControlMessage(cf, toggle); err != nil { if nettest.ProtocolNotSupported(err) { t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } if err := r.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil { t.Fatal(err) } r.SetMulticastTTL(i + 1) if err := r.WriteTo(wh, wb, nil); err != nil { t.Fatal(err) } rb := make([]byte, ipv4.HeaderLen+128) if rh, b, _, err := r.ReadFrom(rb); err != nil { t.Fatal(err) } else { m, err := icmp.ParseMessage(iana.ProtocolICMP, b) if err != nil { t.Fatal(err) } switch { case (rh.Dst.IsLoopback() || rh.Dst.IsLinkLocalUnicast() || rh.Dst.IsGlobalUnicast()) && m.Type == ipv4.ICMPTypeEchoReply && m.Code == 0: // net.inet.icmp.bmcastecho=1 case rh.Dst.IsMulticast() && m.Type == ipv4.ICMPTypeEcho && m.Code == 0: // net.inet.icmp.bmcastecho=0 default: t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0) } } } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/multicastlistener_test.go000066400000000000000000000127731264464372400264750ustar00rootroot00000000000000// Copyright 2012 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 ipv4_test import ( "net" "runtime" "testing" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv4" ) var udpMultipleGroupListenerTests = []net.Addr{ &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}, // see RFC 4727 &net.UDPAddr{IP: net.IPv4(224, 0, 0, 250)}, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 254)}, } func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if testing.Short() { t.Skip("to avoid external network") } for _, gaddr := range udpMultipleGroupListenerTests { c, err := net.ListenPacket("udp4", "0.0.0.0:0") // wildcard address with no reusable port if err != nil { t.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c) var mift []*net.Interface ift, err := net.Interfaces() if err != nil { t.Fatal(err) } for i, ifi := range ift { if _, ok := nettest.IsMulticastCapable("ip4", &ifi); !ok { continue } if err := p.JoinGroup(&ifi, gaddr); err != nil { t.Fatal(err) } mift = append(mift, &ift[i]) } for _, ifi := range mift { if err := p.LeaveGroup(ifi, gaddr); err != nil { t.Fatal(err) } } } } func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if testing.Short() { t.Skip("to avoid external network") } for _, gaddr := range udpMultipleGroupListenerTests { c1, err := net.ListenPacket("udp4", "224.0.0.0:1024") // wildcard address with reusable port if err != nil { t.Fatal(err) } defer c1.Close() c2, err := net.ListenPacket("udp4", "224.0.0.0:1024") // wildcard address with reusable port if err != nil { t.Fatal(err) } defer c2.Close() var ps [2]*ipv4.PacketConn ps[0] = ipv4.NewPacketConn(c1) ps[1] = ipv4.NewPacketConn(c2) var mift []*net.Interface ift, err := net.Interfaces() if err != nil { t.Fatal(err) } for i, ifi := range ift { if _, ok := nettest.IsMulticastCapable("ip4", &ifi); !ok { continue } for _, p := range ps { if err := p.JoinGroup(&ifi, gaddr); err != nil { t.Fatal(err) } } mift = append(mift, &ift[i]) } for _, ifi := range mift { for _, p := range ps { if err := p.LeaveGroup(ifi, gaddr); err != nil { t.Fatal(err) } } } } } func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if testing.Short() { t.Skip("to avoid external network") } gaddr := net.IPAddr{IP: net.IPv4(224, 0, 0, 254)} // see RFC 4727 type ml struct { c *ipv4.PacketConn ifi *net.Interface } var mlt []*ml ift, err := net.Interfaces() if err != nil { t.Fatal(err) } for i, ifi := range ift { ip, ok := nettest.IsMulticastCapable("ip4", &ifi) if !ok { continue } c, err := net.ListenPacket("udp4", ip.String()+":"+"1024") // unicast address with non-reusable port if err != nil { t.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c) if err := p.JoinGroup(&ifi, &gaddr); err != nil { t.Fatal(err) } mlt = append(mlt, &ml{p, &ift[i]}) } for _, m := range mlt { if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil { t.Fatal(err) } } } func TestIPSingleRawConnWithSingleGroupListener(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if testing.Short() { t.Skip("to avoid external network") } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } c, err := net.ListenPacket("ip4:icmp", "0.0.0.0") // wildcard address if err != nil { t.Fatal(err) } defer c.Close() r, err := ipv4.NewRawConn(c) if err != nil { t.Fatal(err) } gaddr := net.IPAddr{IP: net.IPv4(224, 0, 0, 254)} // see RFC 4727 var mift []*net.Interface ift, err := net.Interfaces() if err != nil { t.Fatal(err) } for i, ifi := range ift { if _, ok := nettest.IsMulticastCapable("ip4", &ifi); !ok { continue } if err := r.JoinGroup(&ifi, &gaddr); err != nil { t.Fatal(err) } mift = append(mift, &ift[i]) } for _, ifi := range mift { if err := r.LeaveGroup(ifi, &gaddr); err != nil { t.Fatal(err) } } } func TestIPPerInterfaceSingleRawConnWithSingleGroupListener(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if testing.Short() { t.Skip("to avoid external network") } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } gaddr := net.IPAddr{IP: net.IPv4(224, 0, 0, 254)} // see RFC 4727 type ml struct { c *ipv4.RawConn ifi *net.Interface } var mlt []*ml ift, err := net.Interfaces() if err != nil { t.Fatal(err) } for i, ifi := range ift { ip, ok := nettest.IsMulticastCapable("ip4", &ifi) if !ok { continue } c, err := net.ListenPacket("ip4:253", ip.String()) // unicast address if err != nil { t.Fatal(err) } defer c.Close() r, err := ipv4.NewRawConn(c) if err != nil { t.Fatal(err) } if err := r.JoinGroup(&ifi, &gaddr); err != nil { t.Fatal(err) } mlt = append(mlt, &ml{r, &ift[i]}) } for _, m := range mlt { if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil { t.Fatal(err) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/multicastsockopt_test.go000066400000000000000000000121261264464372400263220ustar00rootroot00000000000000// Copyright 2012 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 ipv4_test import ( "net" "runtime" "testing" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv4" ) var packetConnMulticastSocketOptionTests = []struct { net, proto, addr string grp, src net.Addr }{ {"udp4", "", "224.0.0.0:0", &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}, nil}, // see RFC 4727 {"ip4", ":icmp", "0.0.0.0", &net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}, nil}, // see RFC 4727 {"udp4", "", "232.0.0.0:0", &net.UDPAddr{IP: net.IPv4(232, 0, 1, 249)}, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771 {"ip4", ":icmp", "0.0.0.0", &net.IPAddr{IP: net.IPv4(232, 0, 1, 250)}, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771 } func TestPacketConnMulticastSocketOptions(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris": t.Skipf("not supported on %s", runtime.GOOS) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } m, ok := nettest.SupportsRawIPSocket() for _, tt := range packetConnMulticastSocketOptionTests { if tt.net == "ip4" && !ok { t.Log(m) continue } c, err := net.ListenPacket(tt.net+tt.proto, tt.addr) if err != nil { t.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c) defer p.Close() if tt.src == nil { testMulticastSocketOptions(t, p, ifi, tt.grp) } else { testSourceSpecificMulticastSocketOptions(t, p, ifi, tt.grp, tt.src) } } } var rawConnMulticastSocketOptionTests = []struct { grp, src net.Addr }{ {&net.IPAddr{IP: net.IPv4(224, 0, 0, 250)}, nil}, // see RFC 4727 {&net.IPAddr{IP: net.IPv4(232, 0, 1, 250)}, &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}}, // see RFC 5771 } func TestRawConnMulticastSocketOptions(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris": t.Skipf("not supported on %s", runtime.GOOS) } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } for _, tt := range rawConnMulticastSocketOptionTests { c, err := net.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { t.Fatal(err) } defer c.Close() r, err := ipv4.NewRawConn(c) if err != nil { t.Fatal(err) } defer r.Close() if tt.src == nil { testMulticastSocketOptions(t, r, ifi, tt.grp) } else { testSourceSpecificMulticastSocketOptions(t, r, ifi, tt.grp, tt.src) } } } type testIPv4MulticastConn interface { MulticastTTL() (int, error) SetMulticastTTL(ttl int) error MulticastLoopback() (bool, error) SetMulticastLoopback(bool) error JoinGroup(*net.Interface, net.Addr) error LeaveGroup(*net.Interface, net.Addr) error JoinSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error LeaveSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error ExcludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error IncludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error } func testMulticastSocketOptions(t *testing.T, c testIPv4MulticastConn, ifi *net.Interface, grp net.Addr) { const ttl = 255 if err := c.SetMulticastTTL(ttl); err != nil { t.Error(err) return } if v, err := c.MulticastTTL(); err != nil { t.Error(err) return } else if v != ttl { t.Errorf("got %v; want %v", v, ttl) return } for _, toggle := range []bool{true, false} { if err := c.SetMulticastLoopback(toggle); err != nil { t.Error(err) return } if v, err := c.MulticastLoopback(); err != nil { t.Error(err) return } else if v != toggle { t.Errorf("got %v; want %v", v, toggle) return } } if err := c.JoinGroup(ifi, grp); err != nil { t.Error(err) return } if err := c.LeaveGroup(ifi, grp); err != nil { t.Error(err) return } } func testSourceSpecificMulticastSocketOptions(t *testing.T, c testIPv4MulticastConn, ifi *net.Interface, grp, src net.Addr) { // MCAST_JOIN_GROUP -> MCAST_BLOCK_SOURCE -> MCAST_UNBLOCK_SOURCE -> MCAST_LEAVE_GROUP if err := c.JoinGroup(ifi, grp); err != nil { t.Error(err) return } if err := c.ExcludeSourceSpecificGroup(ifi, grp, src); err != nil { switch runtime.GOOS { case "freebsd", "linux": default: // platforms that don't support IGMPv2/3 fail here t.Logf("not supported on %s", runtime.GOOS) return } t.Error(err) return } if err := c.IncludeSourceSpecificGroup(ifi, grp, src); err != nil { t.Error(err) return } if err := c.LeaveGroup(ifi, grp); err != nil { t.Error(err) return } // MCAST_JOIN_SOURCE_GROUP -> MCAST_LEAVE_SOURCE_GROUP if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil { t.Error(err) return } if err := c.LeaveSourceSpecificGroup(ifi, grp, src); err != nil { t.Error(err) return } // MCAST_JOIN_SOURCE_GROUP -> MCAST_LEAVE_GROUP if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil { t.Error(err) return } if err := c.LeaveGroup(ifi, grp); err != nil { t.Error(err) return } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/packet.go000066400000000000000000000053131264464372400231220ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import ( "net" "syscall" ) // A packetHandler represents the IPv4 datagram handler. type packetHandler struct { c *net.IPConn rawOpt } func (c *packetHandler) ok() bool { return c != nil && c.c != nil } // ReadFrom reads an IPv4 datagram from the endpoint c, copying the // datagram into b. It returns the received datagram as the IPv4 // header h, the payload p and the control message cm. func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) { if !c.ok() { return nil, nil, nil, syscall.EINVAL } oob := newControlMessage(&c.rawOpt) n, oobn, _, src, err := c.c.ReadMsgIP(b, oob) if err != nil { return nil, nil, nil, err } var hs []byte if hs, p, err = slicePacket(b[:n]); err != nil { return nil, nil, nil, err } if h, err = ParseHeader(hs); err != nil { return nil, nil, nil, err } if cm, err = parseControlMessage(oob[:oobn]); err != nil { return nil, nil, nil, err } if src != nil && cm != nil { cm.Src = src.IP } return } func slicePacket(b []byte) (h, p []byte, err error) { if len(b) < HeaderLen { return nil, nil, errHeaderTooShort } hdrlen := int(b[0]&0x0f) << 2 return b[:hdrlen], b[hdrlen:], nil } // WriteTo writes an IPv4 datagram through the endpoint c, copying the // datagram from the IPv4 header h and the payload p. The control // message cm allows the datagram path and the outgoing interface to be // specified. Currently only Darwin and Linux support this. The cm // may be nil if control of the outgoing datagram is not required. // // The IPv4 header h must contain appropriate fields that include: // // Version = ipv4.Version // Len = // TOS = // TotalLen = // ID = platform sets an appropriate value if ID is zero // FragOff = // TTL = // Protocol = // Checksum = platform sets an appropriate value if Checksum is zero // Src = platform sets an appropriate value if Src is nil // Dst = // Options = optional func (c *packetHandler) WriteTo(h *Header, p []byte, cm *ControlMessage) error { if !c.ok() { return syscall.EINVAL } oob := marshalControlMessage(cm) wh, err := h.Marshal() if err != nil { return err } dst := &net.IPAddr{} if cm != nil { if ip := cm.Dst.To4(); ip != nil { dst.IP = ip } } if dst.IP == nil { dst.IP = h.Dst } wh = append(wh, p...) _, _, err = c.c.WriteMsgIP(wh, oob, dst) return err } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/payload.go000066400000000000000000000006051264464372400233030ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import "net" // A payloadHandler represents the IPv4 datagram payload handler. type payloadHandler struct { net.PacketConn rawOpt } func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/payload_cmsg.go000066400000000000000000000044201264464372400243130ustar00rootroot00000000000000// Copyright 2012 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. // +build !plan9,!solaris,!windows package ipv4 import ( "net" "syscall" ) // ReadFrom reads a payload of the received IPv4 datagram, from the // endpoint c, copying the payload into b. It returns the number of // bytes copied into b, the control message cm and the source address // src of the received datagram. func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) { if !c.ok() { return 0, nil, nil, syscall.EINVAL } oob := newControlMessage(&c.rawOpt) var oobn int switch c := c.PacketConn.(type) { case *net.UDPConn: if n, oobn, _, src, err = c.ReadMsgUDP(b, oob); err != nil { return 0, nil, nil, err } case *net.IPConn: if sockOpts[ssoStripHeader].name > 0 { if n, oobn, _, src, err = c.ReadMsgIP(b, oob); err != nil { return 0, nil, nil, err } } else { nb := make([]byte, maxHeaderLen+len(b)) if n, oobn, _, src, err = c.ReadMsgIP(nb, oob); err != nil { return 0, nil, nil, err } hdrlen := int(nb[0]&0x0f) << 2 copy(b, nb[hdrlen:]) n -= hdrlen } default: return 0, nil, nil, errInvalidConnType } if cm, err = parseControlMessage(oob[:oobn]); err != nil { return 0, nil, nil, err } if cm != nil { cm.Src = netAddrToIP4(src) } return } // WriteTo writes a payload of the IPv4 datagram, to the destination // address dst through the endpoint c, copying the payload from b. It // returns the number of bytes written. The control message cm allows // the datagram path and the outgoing interface to be specified. // Currently only Darwin and Linux support this. The cm may be nil if // control of the outgoing datagram is not required. func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) { if !c.ok() { return 0, syscall.EINVAL } oob := marshalControlMessage(cm) if dst == nil { return 0, errMissingAddress } switch c := c.PacketConn.(type) { case *net.UDPConn: n, _, err = c.WriteMsgUDP(b, oob, dst.(*net.UDPAddr)) case *net.IPConn: n, _, err = c.WriteMsgIP(b, oob, dst.(*net.IPAddr)) default: return 0, errInvalidConnType } if err != nil { return 0, err } return } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/payload_nocmsg.go000066400000000000000000000025171264464372400246550ustar00rootroot00000000000000// Copyright 2012 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. // +build plan9 solaris windows package ipv4 import ( "net" "syscall" ) // ReadFrom reads a payload of the received IPv4 datagram, from the // endpoint c, copying the payload into b. It returns the number of // bytes copied into b, the control message cm and the source address // src of the received datagram. func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) { if !c.ok() { return 0, nil, nil, syscall.EINVAL } if n, src, err = c.PacketConn.ReadFrom(b); err != nil { return 0, nil, nil, err } return } // WriteTo writes a payload of the IPv4 datagram, to the destination // address dst through the endpoint c, copying the payload from b. It // returns the number of bytes written. The control message cm allows // the datagram path and the outgoing interface to be specified. // Currently only Darwin and Linux support this. The cm may be nil if // control of the outgoing datagram is not required. func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) { if !c.ok() { return 0, syscall.EINVAL } if dst == nil { return 0, errMissingAddress } return c.PacketConn.WriteTo(b, dst) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/readwrite_test.go000066400000000000000000000074111264464372400247010ustar00rootroot00000000000000// Copyright 2012 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 ipv4_test import ( "bytes" "net" "runtime" "strings" "sync" "testing" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv4" ) func benchmarkUDPListener() (net.PacketConn, net.Addr, error) { c, err := net.ListenPacket("udp4", "127.0.0.1:0") if err != nil { return nil, nil, err } dst, err := net.ResolveUDPAddr("udp4", c.LocalAddr().String()) if err != nil { c.Close() return nil, nil, err } return c, dst, nil } func BenchmarkReadWriteNetUDP(b *testing.B) { c, dst, err := benchmarkUDPListener() if err != nil { b.Fatal(err) } defer c.Close() wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128) b.ResetTimer() for i := 0; i < b.N; i++ { benchmarkReadWriteNetUDP(b, c, wb, rb, dst) } } func benchmarkReadWriteNetUDP(b *testing.B, c net.PacketConn, wb, rb []byte, dst net.Addr) { if _, err := c.WriteTo(wb, dst); err != nil { b.Fatal(err) } if _, _, err := c.ReadFrom(rb); err != nil { b.Fatal(err) } } func BenchmarkReadWriteIPv4UDP(b *testing.B) { c, dst, err := benchmarkUDPListener() if err != nil { b.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c) defer p.Close() cf := ipv4.FlagTTL | ipv4.FlagInterface if err := p.SetControlMessage(cf, true); err != nil { b.Fatal(err) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128) b.ResetTimer() for i := 0; i < b.N; i++ { benchmarkReadWriteIPv4UDP(b, p, wb, rb, dst, ifi) } } func benchmarkReadWriteIPv4UDP(b *testing.B, p *ipv4.PacketConn, wb, rb []byte, dst net.Addr, ifi *net.Interface) { cm := ipv4.ControlMessage{TTL: 1} if ifi != nil { cm.IfIndex = ifi.Index } if n, err := p.WriteTo(wb, &cm, dst); err != nil { b.Fatal(err) } else if n != len(wb) { b.Fatalf("got %v; want %v", n, len(wb)) } if _, _, _, err := p.ReadFrom(rb); err != nil { b.Fatal(err) } } func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } c, err := net.ListenPacket("udp4", "127.0.0.1:0") if err != nil { t.Fatal(err) } defer c.Close() p := ipv4.NewPacketConn(c) defer p.Close() dst, err := net.ResolveUDPAddr("udp4", c.LocalAddr().String()) if err != nil { t.Fatal(err) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) cf := ipv4.FlagTTL | ipv4.FlagSrc | ipv4.FlagDst | ipv4.FlagInterface wb := []byte("HELLO-R-U-THERE") if err := p.SetControlMessage(cf, true); err != nil { // probe before test if nettest.ProtocolNotSupported(err) { t.Skipf("not supported on %s", runtime.GOOS) } t.Fatal(err) } var wg sync.WaitGroup reader := func() { defer wg.Done() rb := make([]byte, 128) if n, cm, _, err := p.ReadFrom(rb); err != nil { t.Error(err) return } else if !bytes.Equal(rb[:n], wb) { t.Errorf("got %v; want %v", rb[:n], wb) return } else { s := cm.String() if strings.Contains(s, ",") { t.Errorf("should be space-separated values: %s", s) } } } writer := func(toggle bool) { defer wg.Done() cm := ipv4.ControlMessage{ Src: net.IPv4(127, 0, 0, 1), } if ifi != nil { cm.IfIndex = ifi.Index } if err := p.SetControlMessage(cf, toggle); err != nil { t.Error(err) return } if n, err := p.WriteTo(wb, &cm, dst); err != nil { t.Error(err) return } else if n != len(wb) { t.Errorf("short write: %v", n) return } } const N = 10 wg.Add(N) for i := 0; i < N; i++ { go reader() } wg.Add(2 * N) for i := 0; i < 2*N; i++ { go writer(i%2 != 0) } wg.Add(N) for i := 0; i < N; i++ { go reader() } wg.Wait() } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt.go000066400000000000000000000033071264464372400233360ustar00rootroot00000000000000// Copyright 2014 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 ipv4 // Sticky socket options const ( ssoTOS = iota // header field for unicast packet ssoTTL // header field for unicast packet ssoMulticastTTL // header field for multicast packet ssoMulticastInterface // outbound interface for multicast packet ssoMulticastLoopback // loopback for multicast packet ssoReceiveTTL // header field on received packet ssoReceiveDst // header field on received packet ssoReceiveInterface // inbound interface on received packet ssoPacketInfo // incbound or outbound packet path ssoHeaderPrepend // ipv4 header prepend ssoStripHeader // strip ipv4 header ssoICMPFilter // icmp filter ssoJoinGroup // any-source multicast ssoLeaveGroup // any-source multicast ssoJoinSourceGroup // source-specific multicast ssoLeaveSourceGroup // source-specific multicast ssoBlockSourceGroup // any-source or source-specific multicast ssoUnblockSourceGroup // any-source or source-specific multicast ssoMax ) // Sticky socket option value types const ( ssoTypeByte = iota + 1 ssoTypeInt ssoTypeInterface ssoTypeICMPFilter ssoTypeIPMreq ssoTypeIPMreqn ssoTypeGroupReq ssoTypeGroupSourceReq ) // A sockOpt represents a binding for sticky socket option. type sockOpt struct { name int // option name, must be equal or greater than 1 typ int // option value type, must be equal or greater than 1 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_asmreq.go000066400000000000000000000031471264464372400247100ustar00rootroot00000000000000// Copyright 2012 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. // +build darwin dragonfly freebsd netbsd openbsd windows package ipv4 import "net" func setIPMreqInterface(mreq *sysIPMreq, ifi *net.Interface) error { if ifi == nil { return nil } ifat, err := ifi.Addrs() if err != nil { return err } for _, ifa := range ifat { switch ifa := ifa.(type) { case *net.IPAddr: if ip := ifa.IP.To4(); ip != nil { copy(mreq.Interface[:], ip) return nil } case *net.IPNet: if ip := ifa.IP.To4(); ip != nil { copy(mreq.Interface[:], ip) return nil } } } return errNoSuchInterface } func netIP4ToInterface(ip net.IP) (*net.Interface, error) { ift, err := net.Interfaces() if err != nil { return nil, err } for _, ifi := range ift { ifat, err := ifi.Addrs() if err != nil { return nil, err } for _, ifa := range ifat { switch ifa := ifa.(type) { case *net.IPAddr: if ip.Equal(ifa.IP) { return &ifi, nil } case *net.IPNet: if ip.Equal(ifa.IP) { return &ifi, nil } } } } return nil, errNoSuchInterface } func netInterfaceToIP4(ifi *net.Interface) (net.IP, error) { if ifi == nil { return net.IPv4zero.To4(), nil } ifat, err := ifi.Addrs() if err != nil { return nil, err } for _, ifa := range ifat { switch ifa := ifa.(type) { case *net.IPAddr: if ip := ifa.IP.To4(); ip != nil { return ip, nil } case *net.IPNet: if ip := ifa.IP.To4(); ip != nil { return ip, nil } } } return nil, errNoSuchInterface } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_asmreq_stub.go000066400000000000000000000010401264464372400257330ustar00rootroot00000000000000// Copyright 2012 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. // +build !darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!windows package ipv4 import "net" func setsockoptIPMreq(fd, name int, ifi *net.Interface, grp net.IP) error { return errOpNoSupport } func getsockoptInterface(fd, name int) (*net.Interface, error) { return nil, errOpNoSupport } func setsockoptInterface(fd, name int, ifi *net.Interface) error { return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_asmreq_unix.go000066400000000000000000000024221264464372400257460ustar00rootroot00000000000000// Copyright 2012 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. // +build darwin dragonfly freebsd netbsd openbsd package ipv4 import ( "net" "os" "unsafe" "golang.org/x/net/internal/iana" ) func setsockoptIPMreq(fd, name int, ifi *net.Interface, grp net.IP) error { mreq := sysIPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}} if err := setIPMreqInterface(&mreq, ifi); err != nil { return err } return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&mreq), sysSizeofIPMreq)) } func getsockoptInterface(fd, name int) (*net.Interface, error) { var b [4]byte l := sysSockoptLen(4) if err := getsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&b[0]), &l); err != nil { return nil, os.NewSyscallError("getsockopt", err) } ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3])) if err != nil { return nil, err } return ifi, nil } func setsockoptInterface(fd, name int, ifi *net.Interface) error { ip, err := netInterfaceToIP4(ifi) if err != nil { return err } var b [4]byte copy(b[:], ip) return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&b[0]), sysSockoptLen(4))) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_asmreq_windows.go000066400000000000000000000025171264464372400264620ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import ( "net" "os" "syscall" "unsafe" "golang.org/x/net/internal/iana" ) func setsockoptIPMreq(fd syscall.Handle, name int, ifi *net.Interface, grp net.IP) error { mreq := sysIPMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}} if err := setIPMreqInterface(&mreq, ifi); err != nil { return err } return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, iana.ProtocolIP, int32(name), (*byte)(unsafe.Pointer(&mreq)), int32(sysSizeofIPMreq))) } func getsockoptInterface(fd syscall.Handle, name int) (*net.Interface, error) { var b [4]byte l := int32(4) if err := syscall.Getsockopt(fd, iana.ProtocolIP, int32(name), (*byte)(unsafe.Pointer(&b[0])), &l); err != nil { return nil, os.NewSyscallError("getsockopt", err) } ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3])) if err != nil { return nil, err } return ifi, nil } func setsockoptInterface(fd syscall.Handle, name int, ifi *net.Interface) error { ip, err := netInterfaceToIP4(ifi) if err != nil { return err } var b [4]byte copy(b[:], ip) return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, iana.ProtocolIP, int32(name), (*byte)(unsafe.Pointer(&b[0])), 4)) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_asmreqn_stub.go000066400000000000000000000006541264464372400261230ustar00rootroot00000000000000// Copyright 2014 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. // +build !darwin,!freebsd,!linux,!windows package ipv4 import "net" func getsockoptIPMreqn(fd, name int) (*net.Interface, error) { return nil, errOpNoSupport } func setsockoptIPMreqn(fd, name int, ifi *net.Interface, grp net.IP) error { return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_asmreqn_unix.go000066400000000000000000000020451264464372400261250ustar00rootroot00000000000000// Copyright 2014 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. // +build darwin freebsd linux package ipv4 import ( "net" "os" "unsafe" "golang.org/x/net/internal/iana" ) func getsockoptIPMreqn(fd, name int) (*net.Interface, error) { var mreqn sysIPMreqn l := sysSockoptLen(sysSizeofIPMreqn) if err := getsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&mreqn), &l); err != nil { return nil, os.NewSyscallError("getsockopt", err) } if mreqn.Ifindex == 0 { return nil, nil } ifi, err := net.InterfaceByIndex(int(mreqn.Ifindex)) if err != nil { return nil, err } return ifi, nil } func setsockoptIPMreqn(fd, name int, ifi *net.Interface, grp net.IP) error { var mreqn sysIPMreqn if ifi != nil { mreqn.Ifindex = int32(ifi.Index) } if grp != nil { mreqn.Multiaddr = [4]byte{grp[0], grp[1], grp[2], grp[3]} } return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, unsafe.Pointer(&mreqn), sysSizeofIPMreqn)) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_ssmreq_stub.go000066400000000000000000000006711264464372400257660ustar00rootroot00000000000000// Copyright 2014 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. // +build !darwin,!freebsd,!linux package ipv4 import "net" func setsockoptGroupReq(fd, name int, ifi *net.Interface, grp net.IP) error { return errOpNoSupport } func setsockoptGroupSourceReq(fd, name int, ifi *net.Interface, grp, src net.IP) error { return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_ssmreq_unix.go000066400000000000000000000027371264464372400260010ustar00rootroot00000000000000// Copyright 2014 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. // +build darwin freebsd linux package ipv4 import ( "net" "os" "unsafe" "golang.org/x/net/internal/iana" ) var freebsd32o64 bool func setsockoptGroupReq(fd, name int, ifi *net.Interface, grp net.IP) error { var gr sysGroupReq if ifi != nil { gr.Interface = uint32(ifi.Index) } gr.setGroup(grp) var p unsafe.Pointer var l sysSockoptLen if freebsd32o64 { var d [sysSizeofGroupReq + 4]byte s := (*[sysSizeofGroupReq]byte)(unsafe.Pointer(&gr)) copy(d[:4], s[:4]) copy(d[8:], s[4:]) p = unsafe.Pointer(&d[0]) l = sysSizeofGroupReq + 4 } else { p = unsafe.Pointer(&gr) l = sysSizeofGroupReq } return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, p, l)) } func setsockoptGroupSourceReq(fd, name int, ifi *net.Interface, grp, src net.IP) error { var gsr sysGroupSourceReq if ifi != nil { gsr.Interface = uint32(ifi.Index) } gsr.setSourceGroup(grp, src) var p unsafe.Pointer var l sysSockoptLen if freebsd32o64 { var d [sysSizeofGroupSourceReq + 4]byte s := (*[sysSizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr)) copy(d[:4], s[:4]) copy(d[8:], s[4:]) p = unsafe.Pointer(&d[0]) l = sysSizeofGroupSourceReq + 4 } else { p = unsafe.Pointer(&gsr) l = sysSizeofGroupSourceReq } return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, name, p, l)) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_stub.go000066400000000000000000000004271264464372400243730ustar00rootroot00000000000000// Copyright 2012 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. // +build nacl plan9 solaris package ipv4 func setInt(fd int, opt *sockOpt, v int) error { return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_unix.go000066400000000000000000000061271264464372400244040ustar00rootroot00000000000000// Copyright 2012 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. // +build darwin dragonfly freebsd linux netbsd openbsd package ipv4 import ( "net" "os" "unsafe" "golang.org/x/net/internal/iana" ) func getInt(fd int, opt *sockOpt) (int, error) { if opt.name < 1 || (opt.typ != ssoTypeByte && opt.typ != ssoTypeInt) { return 0, errOpNoSupport } var i int32 var b byte p := unsafe.Pointer(&i) l := sysSockoptLen(4) if opt.typ == ssoTypeByte { p = unsafe.Pointer(&b) l = sysSockoptLen(1) } if err := getsockopt(fd, iana.ProtocolIP, opt.name, p, &l); err != nil { return 0, os.NewSyscallError("getsockopt", err) } if opt.typ == ssoTypeByte { return int(b), nil } return int(i), nil } func setInt(fd int, opt *sockOpt, v int) error { if opt.name < 1 || (opt.typ != ssoTypeByte && opt.typ != ssoTypeInt) { return errOpNoSupport } i := int32(v) var b byte p := unsafe.Pointer(&i) l := sysSockoptLen(4) if opt.typ == ssoTypeByte { b = byte(v) p = unsafe.Pointer(&b) l = sysSockoptLen(1) } return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolIP, opt.name, p, l)) } func getInterface(fd int, opt *sockOpt) (*net.Interface, error) { if opt.name < 1 { return nil, errOpNoSupport } switch opt.typ { case ssoTypeInterface: return getsockoptInterface(fd, opt.name) case ssoTypeIPMreqn: return getsockoptIPMreqn(fd, opt.name) default: return nil, errOpNoSupport } } func setInterface(fd int, opt *sockOpt, ifi *net.Interface) error { if opt.name < 1 { return errOpNoSupport } switch opt.typ { case ssoTypeInterface: return setsockoptInterface(fd, opt.name, ifi) case ssoTypeIPMreqn: return setsockoptIPMreqn(fd, opt.name, ifi, nil) default: return errOpNoSupport } } func getICMPFilter(fd int, opt *sockOpt) (*ICMPFilter, error) { if opt.name < 1 || opt.typ != ssoTypeICMPFilter { return nil, errOpNoSupport } var f ICMPFilter l := sysSockoptLen(sysSizeofICMPFilter) if err := getsockopt(fd, iana.ProtocolReserved, opt.name, unsafe.Pointer(&f.sysICMPFilter), &l); err != nil { return nil, os.NewSyscallError("getsockopt", err) } return &f, nil } func setICMPFilter(fd int, opt *sockOpt, f *ICMPFilter) error { if opt.name < 1 || opt.typ != ssoTypeICMPFilter { return errOpNoSupport } return os.NewSyscallError("setsockopt", setsockopt(fd, iana.ProtocolReserved, opt.name, unsafe.Pointer(&f.sysICMPFilter), sysSizeofICMPFilter)) } func setGroup(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error { if opt.name < 1 { return errOpNoSupport } switch opt.typ { case ssoTypeIPMreq: return setsockoptIPMreq(fd, opt.name, ifi, grp) case ssoTypeIPMreqn: return setsockoptIPMreqn(fd, opt.name, ifi, grp) case ssoTypeGroupReq: return setsockoptGroupReq(fd, opt.name, ifi, grp) default: return errOpNoSupport } } func setSourceGroup(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error { if opt.name < 1 || opt.typ != ssoTypeGroupSourceReq { return errOpNoSupport } return setsockoptGroupSourceReq(fd, opt.name, ifi, grp, src) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sockopt_windows.go000066400000000000000000000035221264464372400251070ustar00rootroot00000000000000// Copyright 2012 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 ipv4 import ( "net" "os" "syscall" "unsafe" "golang.org/x/net/internal/iana" ) func getInt(fd syscall.Handle, opt *sockOpt) (int, error) { if opt.name < 1 || opt.typ != ssoTypeInt { return 0, errOpNoSupport } var i int32 l := int32(4) if err := syscall.Getsockopt(fd, iana.ProtocolIP, int32(opt.name), (*byte)(unsafe.Pointer(&i)), &l); err != nil { return 0, os.NewSyscallError("getsockopt", err) } return int(i), nil } func setInt(fd syscall.Handle, opt *sockOpt, v int) error { if opt.name < 1 || opt.typ != ssoTypeInt { return errOpNoSupport } i := int32(v) return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, iana.ProtocolIP, int32(opt.name), (*byte)(unsafe.Pointer(&i)), 4)) } func getInterface(fd syscall.Handle, opt *sockOpt) (*net.Interface, error) { if opt.name < 1 || opt.typ != ssoTypeInterface { return nil, errOpNoSupport } return getsockoptInterface(fd, opt.name) } func setInterface(fd syscall.Handle, opt *sockOpt, ifi *net.Interface) error { if opt.name < 1 || opt.typ != ssoTypeInterface { return errOpNoSupport } return setsockoptInterface(fd, opt.name, ifi) } func getICMPFilter(fd syscall.Handle, opt *sockOpt) (*ICMPFilter, error) { return nil, errOpNoSupport } func setICMPFilter(fd syscall.Handle, opt *sockOpt, f *ICMPFilter) error { return errOpNoSupport } func setGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp net.IP) error { if opt.name < 1 || opt.typ != ssoTypeIPMreq { return errOpNoSupport } return setsockoptIPMreq(fd, opt.name, ifi, grp) } func setSourceGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error { // TODO(mikio): implement this return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sys_bsd.go000066400000000000000000000022501264464372400233160ustar00rootroot00000000000000// Copyright 2014 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. // +build dragonfly netbsd package ipv4 import ( "net" "syscall" ) type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{ ctlTTL: {sysIP_RECVTTL, 1, marshalTTL, parseTTL}, ctlDst: {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst}, ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface}, } sockOpts = [ssoMax]sockOpt{ ssoTOS: {sysIP_TOS, ssoTypeInt}, ssoTTL: {sysIP_TTL, ssoTypeInt}, ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte}, ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface}, ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt}, ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt}, ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt}, ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt}, ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt}, ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq}, ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq}, } ) golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sys_darwin.go000066400000000000000000000066021264464372400240370ustar00rootroot00000000000000// Copyright 2014 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 ipv4 import ( "net" "syscall" "unsafe" ) type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{ ctlTTL: {sysIP_RECVTTL, 1, marshalTTL, parseTTL}, ctlDst: {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst}, ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface}, } sockOpts = [ssoMax]sockOpt{ ssoTOS: {sysIP_TOS, ssoTypeInt}, ssoTTL: {sysIP_TTL, ssoTypeInt}, ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte}, ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface}, ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt}, ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt}, ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt}, ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt}, ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt}, ssoStripHeader: {sysIP_STRIPHDR, ssoTypeInt}, ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq}, ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq}, } ) func init() { // Seems like kern.osreldate is veiled on latest OS X. We use // kern.osrelease instead. osver, err := syscall.Sysctl("kern.osrelease") if err != nil { return } var i int for i = range osver { if osver[i] == '.' { break } } // The IP_PKTINFO and protocol-independent multicast API were // introduced in OS X 10.7 (Darwin 11.0.0). But it looks like // those features require OS X 10.8 (Darwin 12.0.0) and above. // See http://support.apple.com/kb/HT1633. if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '2' { ctlOpts[ctlPacketInfo].name = sysIP_PKTINFO ctlOpts[ctlPacketInfo].length = sysSizeofInetPktinfo ctlOpts[ctlPacketInfo].marshal = marshalPacketInfo ctlOpts[ctlPacketInfo].parse = parsePacketInfo sockOpts[ssoPacketInfo].name = sysIP_RECVPKTINFO sockOpts[ssoPacketInfo].typ = ssoTypeInt sockOpts[ssoMulticastInterface].typ = ssoTypeIPMreqn sockOpts[ssoJoinGroup].name = sysMCAST_JOIN_GROUP sockOpts[ssoJoinGroup].typ = ssoTypeGroupReq sockOpts[ssoLeaveGroup].name = sysMCAST_LEAVE_GROUP sockOpts[ssoLeaveGroup].typ = ssoTypeGroupReq sockOpts[ssoJoinSourceGroup].name = sysMCAST_JOIN_SOURCE_GROUP sockOpts[ssoJoinSourceGroup].typ = ssoTypeGroupSourceReq sockOpts[ssoLeaveSourceGroup].name = sysMCAST_LEAVE_SOURCE_GROUP sockOpts[ssoLeaveSourceGroup].typ = ssoTypeGroupSourceReq sockOpts[ssoBlockSourceGroup].name = sysMCAST_BLOCK_SOURCE sockOpts[ssoBlockSourceGroup].typ = ssoTypeGroupSourceReq sockOpts[ssoUnblockSourceGroup].name = sysMCAST_UNBLOCK_SOURCE sockOpts[ssoUnblockSourceGroup].typ = ssoTypeGroupSourceReq } } func (pi *sysInetPktinfo) setIfindex(i int) { pi.Ifindex = uint32(i) } func (gr *sysGroupReq) setGroup(grp net.IP) { sa := (*sysSockaddrInet)(unsafe.Pointer(&gr.Pad_cgo_0[0])) sa.Len = sysSizeofSockaddrInet sa.Family = syscall.AF_INET copy(sa.Addr[:], grp) } func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) { sa := (*sysSockaddrInet)(unsafe.Pointer(&gsr.Pad_cgo_0[0])) sa.Len = sysSizeofSockaddrInet sa.Family = syscall.AF_INET copy(sa.Addr[:], grp) sa = (*sysSockaddrInet)(unsafe.Pointer(&gsr.Pad_cgo_1[0])) sa.Len = sysSizeofSockaddrInet sa.Family = syscall.AF_INET copy(sa.Addr[:], src) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sys_freebsd.go000066400000000000000000000045661264464372400241740ustar00rootroot00000000000000// Copyright 2014 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 ipv4 import ( "net" "runtime" "strings" "syscall" "unsafe" ) type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{ ctlTTL: {sysIP_RECVTTL, 1, marshalTTL, parseTTL}, ctlDst: {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst}, ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface}, } sockOpts = [ssoMax]sockOpt{ ssoTOS: {sysIP_TOS, ssoTypeInt}, ssoTTL: {sysIP_TTL, ssoTypeInt}, ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte}, ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface}, ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt}, ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt}, ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt}, ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt}, ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt}, ssoJoinGroup: {sysMCAST_JOIN_GROUP, ssoTypeGroupReq}, ssoLeaveGroup: {sysMCAST_LEAVE_GROUP, ssoTypeGroupReq}, ssoJoinSourceGroup: {sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq}, ssoLeaveSourceGroup: {sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq}, ssoBlockSourceGroup: {sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq}, ssoUnblockSourceGroup: {sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq}, } ) func init() { freebsdVersion, _ = syscall.SysctlUint32("kern.osreldate") if freebsdVersion >= 1000000 { sockOpts[ssoMulticastInterface].typ = ssoTypeIPMreqn } if runtime.GOOS == "freebsd" && runtime.GOARCH == "386" { archs, _ := syscall.Sysctl("kern.supported_archs") for _, s := range strings.Fields(archs) { if s == "amd64" { freebsd32o64 = true break } } } } func (gr *sysGroupReq) setGroup(grp net.IP) { sa := (*sysSockaddrInet)(unsafe.Pointer(&gr.Group)) sa.Len = sysSizeofSockaddrInet sa.Family = syscall.AF_INET copy(sa.Addr[:], grp) } func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) { sa := (*sysSockaddrInet)(unsafe.Pointer(&gsr.Group)) sa.Len = sysSizeofSockaddrInet sa.Family = syscall.AF_INET copy(sa.Addr[:], grp) sa = (*sysSockaddrInet)(unsafe.Pointer(&gsr.Source)) sa.Len = sysSizeofSockaddrInet sa.Family = syscall.AF_INET copy(sa.Addr[:], src) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sys_linux.go000066400000000000000000000035631264464372400237150ustar00rootroot00000000000000// Copyright 2014 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 ipv4 import ( "net" "syscall" "unsafe" ) type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{ ctlTTL: {sysIP_TTL, 1, marshalTTL, parseTTL}, ctlPacketInfo: {sysIP_PKTINFO, sysSizeofInetPktinfo, marshalPacketInfo, parsePacketInfo}, } sockOpts = [ssoMax]sockOpt{ ssoTOS: {sysIP_TOS, ssoTypeInt}, ssoTTL: {sysIP_TTL, ssoTypeInt}, ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeInt}, ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeIPMreqn}, ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt}, ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt}, ssoPacketInfo: {sysIP_PKTINFO, ssoTypeInt}, ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt}, ssoICMPFilter: {sysICMP_FILTER, ssoTypeICMPFilter}, ssoJoinGroup: {sysMCAST_JOIN_GROUP, ssoTypeGroupReq}, ssoLeaveGroup: {sysMCAST_LEAVE_GROUP, ssoTypeGroupReq}, ssoJoinSourceGroup: {sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq}, ssoLeaveSourceGroup: {sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq}, ssoBlockSourceGroup: {sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq}, ssoUnblockSourceGroup: {sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq}, } ) func (pi *sysInetPktinfo) setIfindex(i int) { pi.Ifindex = int32(i) } func (gr *sysGroupReq) setGroup(grp net.IP) { sa := (*sysSockaddrInet)(unsafe.Pointer(&gr.Group)) sa.Family = syscall.AF_INET copy(sa.Addr[:], grp) } func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) { sa := (*sysSockaddrInet)(unsafe.Pointer(&gsr.Group)) sa.Family = syscall.AF_INET copy(sa.Addr[:], grp) sa = (*sysSockaddrInet)(unsafe.Pointer(&gsr.Source)) sa.Family = syscall.AF_INET copy(sa.Addr[:], src) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sys_openbsd.go000066400000000000000000000022151264464372400242010ustar00rootroot00000000000000// Copyright 2014 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 ipv4 import ( "net" "syscall" ) type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{ ctlTTL: {sysIP_RECVTTL, 1, marshalTTL, parseTTL}, ctlDst: {sysIP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst}, ctlInterface: {sysIP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface}, } sockOpts = [ssoMax]sockOpt{ ssoTOS: {sysIP_TOS, ssoTypeInt}, ssoTTL: {sysIP_TTL, ssoTypeInt}, ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeByte}, ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface}, ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeByte}, ssoReceiveTTL: {sysIP_RECVTTL, ssoTypeInt}, ssoReceiveDst: {sysIP_RECVDSTADDR, ssoTypeInt}, ssoReceiveInterface: {sysIP_RECVIF, ssoTypeInt}, ssoHeaderPrepend: {sysIP_HDRINCL, ssoTypeInt}, ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq}, ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq}, } ) golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sys_stub.go000066400000000000000000000004511264464372400235240ustar00rootroot00000000000000// Copyright 2014 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. // +build nacl plan9 solaris package ipv4 type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{} sockOpts = [ssoMax]sockOpt{} ) golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/sys_windows.go000066400000000000000000000031331264464372400242410ustar00rootroot00000000000000// Copyright 2014 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 ipv4 const ( // See ws2tcpip.h. sysIP_OPTIONS = 0x1 sysIP_HDRINCL = 0x2 sysIP_TOS = 0x3 sysIP_TTL = 0x4 sysIP_MULTICAST_IF = 0x9 sysIP_MULTICAST_TTL = 0xa sysIP_MULTICAST_LOOP = 0xb sysIP_ADD_MEMBERSHIP = 0xc sysIP_DROP_MEMBERSHIP = 0xd sysIP_DONTFRAGMENT = 0xe sysIP_ADD_SOURCE_MEMBERSHIP = 0xf sysIP_DROP_SOURCE_MEMBERSHIP = 0x10 sysIP_PKTINFO = 0x13 sysSizeofInetPktinfo = 0x8 sysSizeofIPMreq = 0x8 sysSizeofIPMreqSource = 0xc ) type sysInetPktinfo struct { Addr [4]byte Ifindex int32 } type sysIPMreq struct { Multiaddr [4]byte Interface [4]byte } type sysIPMreqSource struct { Multiaddr [4]byte Sourceaddr [4]byte Interface [4]byte } // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms738586(v=vs.85).aspx var ( ctlOpts = [ctlMax]ctlOpt{} sockOpts = [ssoMax]sockOpt{ ssoTOS: {sysIP_TOS, ssoTypeInt}, ssoTTL: {sysIP_TTL, ssoTypeInt}, ssoMulticastTTL: {sysIP_MULTICAST_TTL, ssoTypeInt}, ssoMulticastInterface: {sysIP_MULTICAST_IF, ssoTypeInterface}, ssoMulticastLoopback: {sysIP_MULTICAST_LOOP, ssoTypeInt}, ssoJoinGroup: {sysIP_ADD_MEMBERSHIP, ssoTypeIPMreq}, ssoLeaveGroup: {sysIP_DROP_MEMBERSHIP, ssoTypeIPMreq}, } ) func (pi *sysInetPktinfo) setIfindex(i int) { pi.Ifindex = int32(i) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/syscall_linux_386.go000066400000000000000000000015221264464372400251420ustar00rootroot00000000000000// Copyright 2014 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 ipv4 import ( "syscall" "unsafe" ) const ( sysGETSOCKOPT = 0xf sysSETSOCKOPT = 0xe ) func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno) func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error { if _, errno := socketcall(sysGETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 { return error(errno) } return nil } func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error { if _, errno := socketcall(sysSETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 { return error(errno) } return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/syscall_unix.go000066400000000000000000000014571264464372400243750ustar00rootroot00000000000000// Copyright 2014 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. // +build darwin dragonfly freebsd linux,!386 netbsd openbsd package ipv4 import ( "syscall" "unsafe" ) func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error { if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 { return error(errno) } return nil } func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error { if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 { return error(errno) } return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/thunk_linux_386.s000066400000000000000000000003541264464372400244600ustar00rootroot00000000000000// Copyright 2014 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. // +build go1.2 TEXT ·socketcall(SB),4,$0-36 JMP syscall·socketcall(SB) golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/unicast_test.go000066400000000000000000000143601264464372400243620ustar00rootroot00000000000000// Copyright 2012 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 ipv4_test import ( "bytes" "net" "os" "runtime" "testing" "time" "golang.org/x/net/icmp" "golang.org/x/net/internal/iana" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv4" ) func TestPacketConnReadWriteUnicastUDP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } c, err := net.ListenPacket("udp4", "127.0.0.1:0") if err != nil { t.Fatal(err) } defer c.Close() dst, err := net.ResolveUDPAddr("udp4", c.LocalAddr().String()) if err != nil { t.Fatal(err) } p := ipv4.NewPacketConn(c) defer p.Close() cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface wb := []byte("HELLO-R-U-THERE") for i, toggle := range []bool{true, false, true} { if err := p.SetControlMessage(cf, toggle); err != nil { if nettest.ProtocolNotSupported(err) { t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } p.SetTTL(i + 1) if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { t.Fatal(err) } if n, err := p.WriteTo(wb, nil, dst); err != nil { t.Fatal(err) } else if n != len(wb) { t.Fatalf("got %v; want %v", n, len(wb)) } rb := make([]byte, 128) if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { t.Fatal(err) } if n, _, _, err := p.ReadFrom(rb); err != nil { t.Fatal(err) } else if !bytes.Equal(rb[:n], wb) { t.Fatalf("got %v; want %v", rb[:n], wb) } } } func TestPacketConnReadWriteUnicastICMP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } c, err := net.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { t.Fatal(err) } defer c.Close() dst, err := net.ResolveIPAddr("ip4", "127.0.0.1") if err != nil { t.Fatal(err) } p := ipv4.NewPacketConn(c) defer p.Close() cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface for i, toggle := range []bool{true, false, true} { wb, err := (&icmp.Message{ Type: ipv4.ICMPTypeEcho, Code: 0, Body: &icmp.Echo{ ID: os.Getpid() & 0xffff, Seq: i + 1, Data: []byte("HELLO-R-U-THERE"), }, }).Marshal(nil) if err != nil { t.Fatal(err) } if err := p.SetControlMessage(cf, toggle); err != nil { if nettest.ProtocolNotSupported(err) { t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } p.SetTTL(i + 1) if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { t.Fatal(err) } if n, err := p.WriteTo(wb, nil, dst); err != nil { t.Fatal(err) } else if n != len(wb) { t.Fatalf("got %v; want %v", n, len(wb)) } rb := make([]byte, 128) loop: if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { t.Fatal(err) } if n, _, _, err := p.ReadFrom(rb); err != nil { switch runtime.GOOS { case "darwin": // older darwin kernels have some limitation on receiving icmp packet through raw socket t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } else { m, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n]) if err != nil { t.Fatal(err) } if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho { // On Linux we must handle own sent packets. goto loop } if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 { t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0) } } } } func TestRawConnReadWriteUnicastICMP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } c, err := net.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { t.Fatal(err) } defer c.Close() dst, err := net.ResolveIPAddr("ip4", "127.0.0.1") if err != nil { t.Fatal(err) } r, err := ipv4.NewRawConn(c) if err != nil { t.Fatal(err) } defer r.Close() cf := ipv4.FlagTTL | ipv4.FlagDst | ipv4.FlagInterface for i, toggle := range []bool{true, false, true} { wb, err := (&icmp.Message{ Type: ipv4.ICMPTypeEcho, Code: 0, Body: &icmp.Echo{ ID: os.Getpid() & 0xffff, Seq: i + 1, Data: []byte("HELLO-R-U-THERE"), }, }).Marshal(nil) if err != nil { t.Fatal(err) } wh := &ipv4.Header{ Version: ipv4.Version, Len: ipv4.HeaderLen, TOS: i + 1, TotalLen: ipv4.HeaderLen + len(wb), TTL: i + 1, Protocol: 1, Dst: dst.IP, } if err := r.SetControlMessage(cf, toggle); err != nil { if nettest.ProtocolNotSupported(err) { t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } if err := r.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { t.Fatal(err) } if err := r.WriteTo(wh, wb, nil); err != nil { t.Fatal(err) } rb := make([]byte, ipv4.HeaderLen+128) loop: if err := r.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { t.Fatal(err) } if _, b, _, err := r.ReadFrom(rb); err != nil { switch runtime.GOOS { case "darwin": // older darwin kernels have some limitation on receiving icmp packet through raw socket t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } else { m, err := icmp.ParseMessage(iana.ProtocolICMP, b) if err != nil { t.Fatal(err) } if runtime.GOOS == "linux" && m.Type == ipv4.ICMPTypeEcho { // On Linux we must handle own sent packets. goto loop } if m.Type != ipv4.ICMPTypeEchoReply || m.Code != 0 { t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv4.ICMPTypeEchoReply, 0) } } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/unicastsockopt_test.go000066400000000000000000000056741264464372400257750ustar00rootroot00000000000000// Copyright 2012 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 ipv4_test import ( "net" "runtime" "testing" "golang.org/x/net/internal/iana" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv4" ) func TestConnUnicastSocketOptions(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris": t.Skipf("not supported on %s", runtime.GOOS) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } ln, err := net.Listen("tcp4", "127.0.0.1:0") if err != nil { t.Fatal(err) } defer ln.Close() done := make(chan bool) go acceptor(t, ln, done) c, err := net.Dial("tcp4", ln.Addr().String()) if err != nil { t.Fatal(err) } defer c.Close() testUnicastSocketOptions(t, ipv4.NewConn(c)) <-done } var packetConnUnicastSocketOptionTests = []struct { net, proto, addr string }{ {"udp4", "", "127.0.0.1:0"}, {"ip4", ":icmp", "127.0.0.1"}, } func TestPacketConnUnicastSocketOptions(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris": t.Skipf("not supported on %s", runtime.GOOS) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } m, ok := nettest.SupportsRawIPSocket() for _, tt := range packetConnUnicastSocketOptionTests { if tt.net == "ip4" && !ok { t.Log(m) continue } c, err := net.ListenPacket(tt.net+tt.proto, tt.addr) if err != nil { t.Fatal(err) } defer c.Close() testUnicastSocketOptions(t, ipv4.NewPacketConn(c)) } } func TestRawConnUnicastSocketOptions(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris": t.Skipf("not supported on %s", runtime.GOOS) } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } c, err := net.ListenPacket("ip4:icmp", "127.0.0.1") if err != nil { t.Fatal(err) } defer c.Close() r, err := ipv4.NewRawConn(c) if err != nil { t.Fatal(err) } testUnicastSocketOptions(t, r) } type testIPv4UnicastConn interface { TOS() (int, error) SetTOS(int) error TTL() (int, error) SetTTL(int) error } func testUnicastSocketOptions(t *testing.T, c testIPv4UnicastConn) { tos := iana.DiffServCS0 | iana.NotECNTransport switch runtime.GOOS { case "windows": // IP_TOS option is supported on Windows 8 and beyond. t.Skipf("not supported on %s", runtime.GOOS) } if err := c.SetTOS(tos); err != nil { t.Fatal(err) } if v, err := c.TOS(); err != nil { t.Fatal(err) } else if v != tos { t.Fatalf("got %v; want %v", v, tos) } const ttl = 255 if err := c.SetTTL(ttl); err != nil { t.Fatal(err) } if v, err := c.TTL(); err != nil { t.Fatal(err) } else if v != ttl { t.Fatalf("got %v; want %v", v, ttl) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_darwin.go000066400000000000000000000042371264464372400242330ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_darwin.go package ipv4 const ( sysIP_OPTIONS = 0x1 sysIP_HDRINCL = 0x2 sysIP_TOS = 0x3 sysIP_TTL = 0x4 sysIP_RECVOPTS = 0x5 sysIP_RECVRETOPTS = 0x6 sysIP_RECVDSTADDR = 0x7 sysIP_RETOPTS = 0x8 sysIP_RECVIF = 0x14 sysIP_STRIPHDR = 0x17 sysIP_RECVTTL = 0x18 sysIP_BOUND_IF = 0x19 sysIP_PKTINFO = 0x1a sysIP_RECVPKTINFO = 0x1a sysIP_MULTICAST_IF = 0x9 sysIP_MULTICAST_TTL = 0xa sysIP_MULTICAST_LOOP = 0xb sysIP_ADD_MEMBERSHIP = 0xc sysIP_DROP_MEMBERSHIP = 0xd sysIP_MULTICAST_VIF = 0xe sysIP_MULTICAST_IFINDEX = 0x42 sysIP_ADD_SOURCE_MEMBERSHIP = 0x46 sysIP_DROP_SOURCE_MEMBERSHIP = 0x47 sysIP_BLOCK_SOURCE = 0x48 sysIP_UNBLOCK_SOURCE = 0x49 sysMCAST_JOIN_GROUP = 0x50 sysMCAST_LEAVE_GROUP = 0x51 sysMCAST_JOIN_SOURCE_GROUP = 0x52 sysMCAST_LEAVE_SOURCE_GROUP = 0x53 sysMCAST_BLOCK_SOURCE = 0x54 sysMCAST_UNBLOCK_SOURCE = 0x55 sysSizeofSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofInetPktinfo = 0xc sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x84 sysSizeofGroupSourceReq = 0x104 ) type sysSockaddrStorage struct { Len uint8 Family uint8 X__ss_pad1 [6]int8 X__ss_align int64 X__ss_pad2 [112]int8 } type sysSockaddrInet struct { Len uint8 Family uint8 Port uint16 Addr [4]byte /* in_addr */ Zero [8]int8 } type sysInetPktinfo struct { Ifindex uint32 Spec_dst [4]byte /* in_addr */ Addr [4]byte /* in_addr */ } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr [4]byte /* in_addr */ Sourceaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [128]byte } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [128]byte Pad_cgo_1 [128]byte } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_dragonfly.go000066400000000000000000000012271264464372400247300ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_dragonfly.go // +build dragonfly package ipv4 const ( sysIP_OPTIONS = 0x1 sysIP_HDRINCL = 0x2 sysIP_TOS = 0x3 sysIP_TTL = 0x4 sysIP_RECVOPTS = 0x5 sysIP_RECVRETOPTS = 0x6 sysIP_RECVDSTADDR = 0x7 sysIP_RETOPTS = 0x8 sysIP_RECVIF = 0x14 sysIP_RECVTTL = 0x41 sysIP_MULTICAST_IF = 0x9 sysIP_MULTICAST_TTL = 0xa sysIP_MULTICAST_LOOP = 0xb sysIP_MULTICAST_VIF = 0xe sysIP_ADD_MEMBERSHIP = 0xc sysIP_DROP_MEMBERSHIP = 0xd sysSizeofIPMreq = 0x8 ) type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_freebsd_386.go000066400000000000000000000040701264464372400247540ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_freebsd.go package ipv4 const ( sysIP_OPTIONS = 0x1 sysIP_HDRINCL = 0x2 sysIP_TOS = 0x3 sysIP_TTL = 0x4 sysIP_RECVOPTS = 0x5 sysIP_RECVRETOPTS = 0x6 sysIP_RECVDSTADDR = 0x7 sysIP_SENDSRCADDR = 0x7 sysIP_RETOPTS = 0x8 sysIP_RECVIF = 0x14 sysIP_ONESBCAST = 0x17 sysIP_BINDANY = 0x18 sysIP_RECVTTL = 0x41 sysIP_MINTTL = 0x42 sysIP_DONTFRAG = 0x43 sysIP_RECVTOS = 0x44 sysIP_MULTICAST_IF = 0x9 sysIP_MULTICAST_TTL = 0xa sysIP_MULTICAST_LOOP = 0xb sysIP_ADD_MEMBERSHIP = 0xc sysIP_DROP_MEMBERSHIP = 0xd sysIP_MULTICAST_VIF = 0xe sysIP_ADD_SOURCE_MEMBERSHIP = 0x46 sysIP_DROP_SOURCE_MEMBERSHIP = 0x47 sysIP_BLOCK_SOURCE = 0x48 sysIP_UNBLOCK_SOURCE = 0x49 sysMCAST_JOIN_GROUP = 0x50 sysMCAST_LEAVE_GROUP = 0x51 sysMCAST_JOIN_SOURCE_GROUP = 0x52 sysMCAST_LEAVE_SOURCE_GROUP = 0x53 sysMCAST_BLOCK_SOURCE = 0x54 sysMCAST_UNBLOCK_SOURCE = 0x55 sysSizeofSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x84 sysSizeofGroupSourceReq = 0x104 ) type sysSockaddrStorage struct { Len uint8 Family uint8 X__ss_pad1 [6]int8 X__ss_align int64 X__ss_pad2 [112]int8 } type sysSockaddrInet struct { Len uint8 Family uint8 Port uint16 Addr [4]byte /* in_addr */ Zero [8]int8 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr [4]byte /* in_addr */ Sourceaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysGroupReq struct { Interface uint32 Group sysSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Group sysSockaddrStorage Source sysSockaddrStorage } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_freebsd_amd64.go000066400000000000000000000041361264464372400253520ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_freebsd.go package ipv4 const ( sysIP_OPTIONS = 0x1 sysIP_HDRINCL = 0x2 sysIP_TOS = 0x3 sysIP_TTL = 0x4 sysIP_RECVOPTS = 0x5 sysIP_RECVRETOPTS = 0x6 sysIP_RECVDSTADDR = 0x7 sysIP_SENDSRCADDR = 0x7 sysIP_RETOPTS = 0x8 sysIP_RECVIF = 0x14 sysIP_ONESBCAST = 0x17 sysIP_BINDANY = 0x18 sysIP_RECVTTL = 0x41 sysIP_MINTTL = 0x42 sysIP_DONTFRAG = 0x43 sysIP_RECVTOS = 0x44 sysIP_MULTICAST_IF = 0x9 sysIP_MULTICAST_TTL = 0xa sysIP_MULTICAST_LOOP = 0xb sysIP_ADD_MEMBERSHIP = 0xc sysIP_DROP_MEMBERSHIP = 0xd sysIP_MULTICAST_VIF = 0xe sysIP_ADD_SOURCE_MEMBERSHIP = 0x46 sysIP_DROP_SOURCE_MEMBERSHIP = 0x47 sysIP_BLOCK_SOURCE = 0x48 sysIP_UNBLOCK_SOURCE = 0x49 sysMCAST_JOIN_GROUP = 0x50 sysMCAST_LEAVE_GROUP = 0x51 sysMCAST_JOIN_SOURCE_GROUP = 0x52 sysMCAST_LEAVE_SOURCE_GROUP = 0x53 sysMCAST_BLOCK_SOURCE = 0x54 sysMCAST_UNBLOCK_SOURCE = 0x55 sysSizeofSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 ) type sysSockaddrStorage struct { Len uint8 Family uint8 X__ss_pad1 [6]int8 X__ss_align int64 X__ss_pad2 [112]int8 } type sysSockaddrInet struct { Len uint8 Family uint8 Port uint16 Addr [4]byte /* in_addr */ Zero [8]int8 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr [4]byte /* in_addr */ Sourceaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysSockaddrStorage Source sysSockaddrStorage } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_freebsd_arm.go000066400000000000000000000041361264464372400252160ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_freebsd.go package ipv4 const ( sysIP_OPTIONS = 0x1 sysIP_HDRINCL = 0x2 sysIP_TOS = 0x3 sysIP_TTL = 0x4 sysIP_RECVOPTS = 0x5 sysIP_RECVRETOPTS = 0x6 sysIP_RECVDSTADDR = 0x7 sysIP_SENDSRCADDR = 0x7 sysIP_RETOPTS = 0x8 sysIP_RECVIF = 0x14 sysIP_ONESBCAST = 0x17 sysIP_BINDANY = 0x18 sysIP_RECVTTL = 0x41 sysIP_MINTTL = 0x42 sysIP_DONTFRAG = 0x43 sysIP_RECVTOS = 0x44 sysIP_MULTICAST_IF = 0x9 sysIP_MULTICAST_TTL = 0xa sysIP_MULTICAST_LOOP = 0xb sysIP_ADD_MEMBERSHIP = 0xc sysIP_DROP_MEMBERSHIP = 0xd sysIP_MULTICAST_VIF = 0xe sysIP_ADD_SOURCE_MEMBERSHIP = 0x46 sysIP_DROP_SOURCE_MEMBERSHIP = 0x47 sysIP_BLOCK_SOURCE = 0x48 sysIP_UNBLOCK_SOURCE = 0x49 sysMCAST_JOIN_GROUP = 0x50 sysMCAST_LEAVE_GROUP = 0x51 sysMCAST_JOIN_SOURCE_GROUP = 0x52 sysMCAST_LEAVE_SOURCE_GROUP = 0x53 sysMCAST_BLOCK_SOURCE = 0x54 sysMCAST_UNBLOCK_SOURCE = 0x55 sysSizeofSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 ) type sysSockaddrStorage struct { Len uint8 Family uint8 X__ss_pad1 [6]int8 X__ss_align int64 X__ss_pad2 [112]int8 } type sysSockaddrInet struct { Len uint8 Family uint8 Port uint16 Addr [4]byte /* in_addr */ Zero [8]int8 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr [4]byte /* in_addr */ Sourceaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysSockaddrStorage Source sysSockaddrStorage } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_linux_386.go000066400000000000000000000056321264464372400245060ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go package ipv4 const ( sysIP_TOS = 0x1 sysIP_TTL = 0x2 sysIP_HDRINCL = 0x3 sysIP_OPTIONS = 0x4 sysIP_ROUTER_ALERT = 0x5 sysIP_RECVOPTS = 0x6 sysIP_RETOPTS = 0x7 sysIP_PKTINFO = 0x8 sysIP_PKTOPTIONS = 0x9 sysIP_MTU_DISCOVER = 0xa sysIP_RECVERR = 0xb sysIP_RECVTTL = 0xc sysIP_RECVTOS = 0xd sysIP_MTU = 0xe sysIP_FREEBIND = 0xf sysIP_TRANSPARENT = 0x13 sysIP_RECVRETOPTS = 0x7 sysIP_ORIGDSTADDR = 0x14 sysIP_RECVORIGDSTADDR = 0x14 sysIP_MINTTL = 0x15 sysIP_NODEFRAG = 0x16 sysIP_UNICAST_IF = 0x32 sysIP_MULTICAST_IF = 0x20 sysIP_MULTICAST_TTL = 0x21 sysIP_MULTICAST_LOOP = 0x22 sysIP_ADD_MEMBERSHIP = 0x23 sysIP_DROP_MEMBERSHIP = 0x24 sysIP_UNBLOCK_SOURCE = 0x25 sysIP_BLOCK_SOURCE = 0x26 sysIP_ADD_SOURCE_MEMBERSHIP = 0x27 sysIP_DROP_SOURCE_MEMBERSHIP = 0x28 sysIP_MSFILTER = 0x29 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIP_MULTICAST_ALL = 0x31 sysICMP_FILTER = 0x1 sysSO_EE_ORIGIN_NONE = 0x0 sysSO_EE_ORIGIN_LOCAL = 0x1 sysSO_EE_ORIGIN_ICMP = 0x2 sysSO_EE_ORIGIN_ICMP6 = 0x3 sysSO_EE_ORIGIN_TXSTATUS = 0x4 sysSO_EE_ORIGIN_TIMESTAMPING = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofInetPktinfo = 0xc sysSizeofSockExtendedErr = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x84 sysSizeofGroupSourceReq = 0x104 sysSizeofICMPFilter = 0x4 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet struct { Family uint16 Port uint16 Addr [4]byte /* in_addr */ X__pad [8]uint8 } type sysInetPktinfo struct { Ifindex int32 Spec_dst [4]byte /* in_addr */ Addr [4]byte /* in_addr */ } type sysSockExtendedErr struct { Errno uint32 Origin uint8 Type uint8 Code uint8 Pad uint8 Info uint32 Data uint32 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr uint32 Interface uint32 Sourceaddr uint32 } type sysGroupReq struct { Interface uint32 Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPFilter struct { Data uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_linux_amd64.go000066400000000000000000000057001264464372400250750ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go package ipv4 const ( sysIP_TOS = 0x1 sysIP_TTL = 0x2 sysIP_HDRINCL = 0x3 sysIP_OPTIONS = 0x4 sysIP_ROUTER_ALERT = 0x5 sysIP_RECVOPTS = 0x6 sysIP_RETOPTS = 0x7 sysIP_PKTINFO = 0x8 sysIP_PKTOPTIONS = 0x9 sysIP_MTU_DISCOVER = 0xa sysIP_RECVERR = 0xb sysIP_RECVTTL = 0xc sysIP_RECVTOS = 0xd sysIP_MTU = 0xe sysIP_FREEBIND = 0xf sysIP_TRANSPARENT = 0x13 sysIP_RECVRETOPTS = 0x7 sysIP_ORIGDSTADDR = 0x14 sysIP_RECVORIGDSTADDR = 0x14 sysIP_MINTTL = 0x15 sysIP_NODEFRAG = 0x16 sysIP_UNICAST_IF = 0x32 sysIP_MULTICAST_IF = 0x20 sysIP_MULTICAST_TTL = 0x21 sysIP_MULTICAST_LOOP = 0x22 sysIP_ADD_MEMBERSHIP = 0x23 sysIP_DROP_MEMBERSHIP = 0x24 sysIP_UNBLOCK_SOURCE = 0x25 sysIP_BLOCK_SOURCE = 0x26 sysIP_ADD_SOURCE_MEMBERSHIP = 0x27 sysIP_DROP_SOURCE_MEMBERSHIP = 0x28 sysIP_MSFILTER = 0x29 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIP_MULTICAST_ALL = 0x31 sysICMP_FILTER = 0x1 sysSO_EE_ORIGIN_NONE = 0x0 sysSO_EE_ORIGIN_LOCAL = 0x1 sysSO_EE_ORIGIN_ICMP = 0x2 sysSO_EE_ORIGIN_ICMP6 = 0x3 sysSO_EE_ORIGIN_TXSTATUS = 0x4 sysSO_EE_ORIGIN_TIMESTAMPING = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofInetPktinfo = 0xc sysSizeofSockExtendedErr = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPFilter = 0x4 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet struct { Family uint16 Port uint16 Addr [4]byte /* in_addr */ X__pad [8]uint8 } type sysInetPktinfo struct { Ifindex int32 Spec_dst [4]byte /* in_addr */ Addr [4]byte /* in_addr */ } type sysSockExtendedErr struct { Errno uint32 Origin uint8 Type uint8 Code uint8 Pad uint8 Info uint32 Data uint32 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr uint32 Interface uint32 Sourceaddr uint32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPFilter struct { Data uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_linux_arm.go000066400000000000000000000056321264464372400247450ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go package ipv4 const ( sysIP_TOS = 0x1 sysIP_TTL = 0x2 sysIP_HDRINCL = 0x3 sysIP_OPTIONS = 0x4 sysIP_ROUTER_ALERT = 0x5 sysIP_RECVOPTS = 0x6 sysIP_RETOPTS = 0x7 sysIP_PKTINFO = 0x8 sysIP_PKTOPTIONS = 0x9 sysIP_MTU_DISCOVER = 0xa sysIP_RECVERR = 0xb sysIP_RECVTTL = 0xc sysIP_RECVTOS = 0xd sysIP_MTU = 0xe sysIP_FREEBIND = 0xf sysIP_TRANSPARENT = 0x13 sysIP_RECVRETOPTS = 0x7 sysIP_ORIGDSTADDR = 0x14 sysIP_RECVORIGDSTADDR = 0x14 sysIP_MINTTL = 0x15 sysIP_NODEFRAG = 0x16 sysIP_UNICAST_IF = 0x32 sysIP_MULTICAST_IF = 0x20 sysIP_MULTICAST_TTL = 0x21 sysIP_MULTICAST_LOOP = 0x22 sysIP_ADD_MEMBERSHIP = 0x23 sysIP_DROP_MEMBERSHIP = 0x24 sysIP_UNBLOCK_SOURCE = 0x25 sysIP_BLOCK_SOURCE = 0x26 sysIP_ADD_SOURCE_MEMBERSHIP = 0x27 sysIP_DROP_SOURCE_MEMBERSHIP = 0x28 sysIP_MSFILTER = 0x29 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIP_MULTICAST_ALL = 0x31 sysICMP_FILTER = 0x1 sysSO_EE_ORIGIN_NONE = 0x0 sysSO_EE_ORIGIN_LOCAL = 0x1 sysSO_EE_ORIGIN_ICMP = 0x2 sysSO_EE_ORIGIN_ICMP6 = 0x3 sysSO_EE_ORIGIN_TXSTATUS = 0x4 sysSO_EE_ORIGIN_TIMESTAMPING = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofInetPktinfo = 0xc sysSizeofSockExtendedErr = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x84 sysSizeofGroupSourceReq = 0x104 sysSizeofICMPFilter = 0x4 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet struct { Family uint16 Port uint16 Addr [4]byte /* in_addr */ X__pad [8]uint8 } type sysInetPktinfo struct { Ifindex int32 Spec_dst [4]byte /* in_addr */ Addr [4]byte /* in_addr */ } type sysSockExtendedErr struct { Errno uint32 Origin uint8 Type uint8 Code uint8 Pad uint8 Info uint32 Data uint32 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr uint32 Interface uint32 Sourceaddr uint32 } type sysGroupReq struct { Interface uint32 Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPFilter struct { Data uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_linux_arm64.go000066400000000000000000000057271264464372400251240ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go // +build linux,arm64 package ipv4 const ( sysIP_TOS = 0x1 sysIP_TTL = 0x2 sysIP_HDRINCL = 0x3 sysIP_OPTIONS = 0x4 sysIP_ROUTER_ALERT = 0x5 sysIP_RECVOPTS = 0x6 sysIP_RETOPTS = 0x7 sysIP_PKTINFO = 0x8 sysIP_PKTOPTIONS = 0x9 sysIP_MTU_DISCOVER = 0xa sysIP_RECVERR = 0xb sysIP_RECVTTL = 0xc sysIP_RECVTOS = 0xd sysIP_MTU = 0xe sysIP_FREEBIND = 0xf sysIP_TRANSPARENT = 0x13 sysIP_RECVRETOPTS = 0x7 sysIP_ORIGDSTADDR = 0x14 sysIP_RECVORIGDSTADDR = 0x14 sysIP_MINTTL = 0x15 sysIP_NODEFRAG = 0x16 sysIP_UNICAST_IF = 0x32 sysIP_MULTICAST_IF = 0x20 sysIP_MULTICAST_TTL = 0x21 sysIP_MULTICAST_LOOP = 0x22 sysIP_ADD_MEMBERSHIP = 0x23 sysIP_DROP_MEMBERSHIP = 0x24 sysIP_UNBLOCK_SOURCE = 0x25 sysIP_BLOCK_SOURCE = 0x26 sysIP_ADD_SOURCE_MEMBERSHIP = 0x27 sysIP_DROP_SOURCE_MEMBERSHIP = 0x28 sysIP_MSFILTER = 0x29 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIP_MULTICAST_ALL = 0x31 sysICMP_FILTER = 0x1 sysSO_EE_ORIGIN_NONE = 0x0 sysSO_EE_ORIGIN_LOCAL = 0x1 sysSO_EE_ORIGIN_ICMP = 0x2 sysSO_EE_ORIGIN_ICMP6 = 0x3 sysSO_EE_ORIGIN_TXSTATUS = 0x4 sysSO_EE_ORIGIN_TIMESTAMPING = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofInetPktinfo = 0xc sysSizeofSockExtendedErr = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPFilter = 0x4 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet struct { Family uint16 Port uint16 Addr [4]byte /* in_addr */ X__pad [8]uint8 } type sysInetPktinfo struct { Ifindex int32 Spec_dst [4]byte /* in_addr */ Addr [4]byte /* in_addr */ } type sysSockExtendedErr struct { Errno uint32 Origin uint8 Type uint8 Code uint8 Pad uint8 Info uint32 Data uint32 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr uint32 Interface uint32 Sourceaddr uint32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPFilter struct { Data uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_linux_mips64.go000066400000000000000000000057301264464372400253070ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go // +build linux,mips64 package ipv4 const ( sysIP_TOS = 0x1 sysIP_TTL = 0x2 sysIP_HDRINCL = 0x3 sysIP_OPTIONS = 0x4 sysIP_ROUTER_ALERT = 0x5 sysIP_RECVOPTS = 0x6 sysIP_RETOPTS = 0x7 sysIP_PKTINFO = 0x8 sysIP_PKTOPTIONS = 0x9 sysIP_MTU_DISCOVER = 0xa sysIP_RECVERR = 0xb sysIP_RECVTTL = 0xc sysIP_RECVTOS = 0xd sysIP_MTU = 0xe sysIP_FREEBIND = 0xf sysIP_TRANSPARENT = 0x13 sysIP_RECVRETOPTS = 0x7 sysIP_ORIGDSTADDR = 0x14 sysIP_RECVORIGDSTADDR = 0x14 sysIP_MINTTL = 0x15 sysIP_NODEFRAG = 0x16 sysIP_UNICAST_IF = 0x32 sysIP_MULTICAST_IF = 0x20 sysIP_MULTICAST_TTL = 0x21 sysIP_MULTICAST_LOOP = 0x22 sysIP_ADD_MEMBERSHIP = 0x23 sysIP_DROP_MEMBERSHIP = 0x24 sysIP_UNBLOCK_SOURCE = 0x25 sysIP_BLOCK_SOURCE = 0x26 sysIP_ADD_SOURCE_MEMBERSHIP = 0x27 sysIP_DROP_SOURCE_MEMBERSHIP = 0x28 sysIP_MSFILTER = 0x29 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIP_MULTICAST_ALL = 0x31 sysICMP_FILTER = 0x1 sysSO_EE_ORIGIN_NONE = 0x0 sysSO_EE_ORIGIN_LOCAL = 0x1 sysSO_EE_ORIGIN_ICMP = 0x2 sysSO_EE_ORIGIN_ICMP6 = 0x3 sysSO_EE_ORIGIN_TXSTATUS = 0x4 sysSO_EE_ORIGIN_TIMESTAMPING = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofInetPktinfo = 0xc sysSizeofSockExtendedErr = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPFilter = 0x4 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet struct { Family uint16 Port uint16 Addr [4]byte /* in_addr */ X__pad [8]uint8 } type sysInetPktinfo struct { Ifindex int32 Spec_dst [4]byte /* in_addr */ Addr [4]byte /* in_addr */ } type sysSockExtendedErr struct { Errno uint32 Origin uint8 Type uint8 Code uint8 Pad uint8 Info uint32 Data uint32 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr uint32 Interface uint32 Sourceaddr uint32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPFilter struct { Data uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_linux_mips64le.go000066400000000000000000000057321264464372400256320ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go // +build linux,mips64le package ipv4 const ( sysIP_TOS = 0x1 sysIP_TTL = 0x2 sysIP_HDRINCL = 0x3 sysIP_OPTIONS = 0x4 sysIP_ROUTER_ALERT = 0x5 sysIP_RECVOPTS = 0x6 sysIP_RETOPTS = 0x7 sysIP_PKTINFO = 0x8 sysIP_PKTOPTIONS = 0x9 sysIP_MTU_DISCOVER = 0xa sysIP_RECVERR = 0xb sysIP_RECVTTL = 0xc sysIP_RECVTOS = 0xd sysIP_MTU = 0xe sysIP_FREEBIND = 0xf sysIP_TRANSPARENT = 0x13 sysIP_RECVRETOPTS = 0x7 sysIP_ORIGDSTADDR = 0x14 sysIP_RECVORIGDSTADDR = 0x14 sysIP_MINTTL = 0x15 sysIP_NODEFRAG = 0x16 sysIP_UNICAST_IF = 0x32 sysIP_MULTICAST_IF = 0x20 sysIP_MULTICAST_TTL = 0x21 sysIP_MULTICAST_LOOP = 0x22 sysIP_ADD_MEMBERSHIP = 0x23 sysIP_DROP_MEMBERSHIP = 0x24 sysIP_UNBLOCK_SOURCE = 0x25 sysIP_BLOCK_SOURCE = 0x26 sysIP_ADD_SOURCE_MEMBERSHIP = 0x27 sysIP_DROP_SOURCE_MEMBERSHIP = 0x28 sysIP_MSFILTER = 0x29 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIP_MULTICAST_ALL = 0x31 sysICMP_FILTER = 0x1 sysSO_EE_ORIGIN_NONE = 0x0 sysSO_EE_ORIGIN_LOCAL = 0x1 sysSO_EE_ORIGIN_ICMP = 0x2 sysSO_EE_ORIGIN_ICMP6 = 0x3 sysSO_EE_ORIGIN_TXSTATUS = 0x4 sysSO_EE_ORIGIN_TIMESTAMPING = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofInetPktinfo = 0xc sysSizeofSockExtendedErr = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPFilter = 0x4 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet struct { Family uint16 Port uint16 Addr [4]byte /* in_addr */ X__pad [8]uint8 } type sysInetPktinfo struct { Ifindex int32 Spec_dst [4]byte /* in_addr */ Addr [4]byte /* in_addr */ } type sysSockExtendedErr struct { Errno uint32 Origin uint8 Type uint8 Code uint8 Pad uint8 Info uint32 Data uint32 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr uint32 Interface uint32 Sourceaddr uint32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPFilter struct { Data uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_linux_ppc64.go000066400000000000000000000057271264464372400251270ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go // +build linux,ppc64 package ipv4 const ( sysIP_TOS = 0x1 sysIP_TTL = 0x2 sysIP_HDRINCL = 0x3 sysIP_OPTIONS = 0x4 sysIP_ROUTER_ALERT = 0x5 sysIP_RECVOPTS = 0x6 sysIP_RETOPTS = 0x7 sysIP_PKTINFO = 0x8 sysIP_PKTOPTIONS = 0x9 sysIP_MTU_DISCOVER = 0xa sysIP_RECVERR = 0xb sysIP_RECVTTL = 0xc sysIP_RECVTOS = 0xd sysIP_MTU = 0xe sysIP_FREEBIND = 0xf sysIP_TRANSPARENT = 0x13 sysIP_RECVRETOPTS = 0x7 sysIP_ORIGDSTADDR = 0x14 sysIP_RECVORIGDSTADDR = 0x14 sysIP_MINTTL = 0x15 sysIP_NODEFRAG = 0x16 sysIP_UNICAST_IF = 0x32 sysIP_MULTICAST_IF = 0x20 sysIP_MULTICAST_TTL = 0x21 sysIP_MULTICAST_LOOP = 0x22 sysIP_ADD_MEMBERSHIP = 0x23 sysIP_DROP_MEMBERSHIP = 0x24 sysIP_UNBLOCK_SOURCE = 0x25 sysIP_BLOCK_SOURCE = 0x26 sysIP_ADD_SOURCE_MEMBERSHIP = 0x27 sysIP_DROP_SOURCE_MEMBERSHIP = 0x28 sysIP_MSFILTER = 0x29 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIP_MULTICAST_ALL = 0x31 sysICMP_FILTER = 0x1 sysSO_EE_ORIGIN_NONE = 0x0 sysSO_EE_ORIGIN_LOCAL = 0x1 sysSO_EE_ORIGIN_ICMP = 0x2 sysSO_EE_ORIGIN_ICMP6 = 0x3 sysSO_EE_ORIGIN_TXSTATUS = 0x4 sysSO_EE_ORIGIN_TIMESTAMPING = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofInetPktinfo = 0xc sysSizeofSockExtendedErr = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPFilter = 0x4 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet struct { Family uint16 Port uint16 Addr [4]byte /* in_addr */ X__pad [8]uint8 } type sysInetPktinfo struct { Ifindex int32 Spec_dst [4]byte /* in_addr */ Addr [4]byte /* in_addr */ } type sysSockExtendedErr struct { Errno uint32 Origin uint8 Type uint8 Code uint8 Pad uint8 Info uint32 Data uint32 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr uint32 Interface uint32 Sourceaddr uint32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPFilter struct { Data uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_linux_ppc64le.go000066400000000000000000000057311264464372400254430ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go // +build linux,ppc64le package ipv4 const ( sysIP_TOS = 0x1 sysIP_TTL = 0x2 sysIP_HDRINCL = 0x3 sysIP_OPTIONS = 0x4 sysIP_ROUTER_ALERT = 0x5 sysIP_RECVOPTS = 0x6 sysIP_RETOPTS = 0x7 sysIP_PKTINFO = 0x8 sysIP_PKTOPTIONS = 0x9 sysIP_MTU_DISCOVER = 0xa sysIP_RECVERR = 0xb sysIP_RECVTTL = 0xc sysIP_RECVTOS = 0xd sysIP_MTU = 0xe sysIP_FREEBIND = 0xf sysIP_TRANSPARENT = 0x13 sysIP_RECVRETOPTS = 0x7 sysIP_ORIGDSTADDR = 0x14 sysIP_RECVORIGDSTADDR = 0x14 sysIP_MINTTL = 0x15 sysIP_NODEFRAG = 0x16 sysIP_UNICAST_IF = 0x32 sysIP_MULTICAST_IF = 0x20 sysIP_MULTICAST_TTL = 0x21 sysIP_MULTICAST_LOOP = 0x22 sysIP_ADD_MEMBERSHIP = 0x23 sysIP_DROP_MEMBERSHIP = 0x24 sysIP_UNBLOCK_SOURCE = 0x25 sysIP_BLOCK_SOURCE = 0x26 sysIP_ADD_SOURCE_MEMBERSHIP = 0x27 sysIP_DROP_SOURCE_MEMBERSHIP = 0x28 sysIP_MSFILTER = 0x29 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIP_MULTICAST_ALL = 0x31 sysICMP_FILTER = 0x1 sysSO_EE_ORIGIN_NONE = 0x0 sysSO_EE_ORIGIN_LOCAL = 0x1 sysSO_EE_ORIGIN_ICMP = 0x2 sysSO_EE_ORIGIN_ICMP6 = 0x3 sysSO_EE_ORIGIN_TXSTATUS = 0x4 sysSO_EE_ORIGIN_TIMESTAMPING = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet = 0x10 sysSizeofInetPktinfo = 0xc sysSizeofSockExtendedErr = 0x10 sysSizeofIPMreq = 0x8 sysSizeofIPMreqn = 0xc sysSizeofIPMreqSource = 0xc sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPFilter = 0x4 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet struct { Family uint16 Port uint16 Addr [4]byte /* in_addr */ X__pad [8]uint8 } type sysInetPktinfo struct { Ifindex int32 Spec_dst [4]byte /* in_addr */ Addr [4]byte /* in_addr */ } type sysSockExtendedErr struct { Errno uint32 Origin uint8 Type uint8 Code uint8 Pad uint8 Info uint32 Data uint32 } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqn struct { Multiaddr [4]byte /* in_addr */ Address [4]byte /* in_addr */ Ifindex int32 } type sysIPMreqSource struct { Multiaddr uint32 Interface uint32 Sourceaddr uint32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPFilter struct { Data uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_netbsd.go000066400000000000000000000011421264464372400242160ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_netbsd.go package ipv4 const ( sysIP_OPTIONS = 0x1 sysIP_HDRINCL = 0x2 sysIP_TOS = 0x3 sysIP_TTL = 0x4 sysIP_RECVOPTS = 0x5 sysIP_RECVRETOPTS = 0x6 sysIP_RECVDSTADDR = 0x7 sysIP_RETOPTS = 0x8 sysIP_RECVIF = 0x14 sysIP_RECVTTL = 0x17 sysIP_MULTICAST_IF = 0x9 sysIP_MULTICAST_TTL = 0xa sysIP_MULTICAST_LOOP = 0xb sysIP_ADD_MEMBERSHIP = 0xc sysIP_DROP_MEMBERSHIP = 0xd sysSizeofIPMreq = 0x8 ) type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_openbsd.go000066400000000000000000000011431264464372400243720ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_openbsd.go package ipv4 const ( sysIP_OPTIONS = 0x1 sysIP_HDRINCL = 0x2 sysIP_TOS = 0x3 sysIP_TTL = 0x4 sysIP_RECVOPTS = 0x5 sysIP_RECVRETOPTS = 0x6 sysIP_RECVDSTADDR = 0x7 sysIP_RETOPTS = 0x8 sysIP_RECVIF = 0x1e sysIP_RECVTTL = 0x1f sysIP_MULTICAST_IF = 0x9 sysIP_MULTICAST_TTL = 0xa sysIP_MULTICAST_LOOP = 0xb sysIP_ADD_MEMBERSHIP = 0xc sysIP_DROP_MEMBERSHIP = 0xd sysSizeofIPMreq = 0x8 ) type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv4/zsys_solaris.go000066400000000000000000000025671264464372400244270ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_solaris.go // +build solaris package ipv4 const ( sysIP_OPTIONS = 0x1 sysIP_HDRINCL = 0x2 sysIP_TOS = 0x3 sysIP_TTL = 0x4 sysIP_RECVOPTS = 0x5 sysIP_RECVRETOPTS = 0x6 sysIP_RECVDSTADDR = 0x7 sysIP_RETOPTS = 0x8 sysIP_RECVIF = 0x9 sysIP_RECVSLLA = 0xa sysIP_RECVTTL = 0xb sysIP_NEXTHOP = 0x19 sysIP_PKTINFO = 0x1a sysIP_RECVPKTINFO = 0x1a sysIP_DONTFRAG = 0x1b sysIP_BOUND_IF = 0x41 sysIP_UNSPEC_SRC = 0x42 sysIP_BROADCAST_TTL = 0x43 sysIP_DHCPINIT_IF = 0x45 sysIP_MULTICAST_IF = 0x10 sysIP_MULTICAST_TTL = 0x11 sysIP_MULTICAST_LOOP = 0x12 sysIP_ADD_MEMBERSHIP = 0x13 sysIP_DROP_MEMBERSHIP = 0x14 sysIP_BLOCK_SOURCE = 0x15 sysIP_UNBLOCK_SOURCE = 0x16 sysIP_ADD_SOURCE_MEMBERSHIP = 0x17 sysIP_DROP_SOURCE_MEMBERSHIP = 0x18 sysSizeofInetPktinfo = 0xc sysSizeofIPMreq = 0x8 sysSizeofIPMreqSource = 0xc ) type sysInetPktinfo struct { Ifindex uint32 Spec_dst [4]byte /* in_addr */ Addr [4]byte /* in_addr */ } type sysIPMreq struct { Multiaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } type sysIPMreqSource struct { Multiaddr [4]byte /* in_addr */ Sourceaddr [4]byte /* in_addr */ Interface [4]byte /* in_addr */ } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/000077500000000000000000000000001264464372400213245ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/control.go000066400000000000000000000060121264464372400233320ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import ( "fmt" "net" "sync" ) // Note that RFC 3542 obsoletes RFC 2292 but OS X Snow Leopard and the // former still support RFC 2292 only. Please be aware that almost // all protocol implementations prohibit using a combination of RFC // 2292 and RFC 3542 for some practical reasons. type rawOpt struct { sync.RWMutex cflags ControlFlags } func (c *rawOpt) set(f ControlFlags) { c.cflags |= f } func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f } func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 } // A ControlFlags represents per packet basis IP-level socket option // control flags. type ControlFlags uint const ( FlagTrafficClass ControlFlags = 1 << iota // pass the traffic class on the received packet FlagHopLimit // pass the hop limit on the received packet FlagSrc // pass the source address on the received packet FlagDst // pass the destination address on the received packet FlagInterface // pass the interface index on the received packet FlagPathMTU // pass the path MTU on the received packet path ) const flagPacketInfo = FlagDst | FlagInterface // A ControlMessage represents per packet basis IP-level socket // options. type ControlMessage struct { // Receiving socket options: SetControlMessage allows to // receive the options from the protocol stack using ReadFrom // method of PacketConn. // // Specifying socket options: ControlMessage for WriteTo // method of PacketConn allows to send the options to the // protocol stack. // TrafficClass int // traffic class, must be 1 <= value <= 255 when specifying HopLimit int // hop limit, must be 1 <= value <= 255 when specifying Src net.IP // source address, specifying only Dst net.IP // destination address, receiving only IfIndex int // interface index, must be 1 <= value when specifying NextHop net.IP // next hop address, specifying only MTU int // path MTU, receiving only } func (cm *ControlMessage) String() string { if cm == nil { return "" } return fmt.Sprintf("tclass=%#x hoplim=%d src=%v dst=%v ifindex=%d nexthop=%v mtu=%d", cm.TrafficClass, cm.HopLimit, cm.Src, cm.Dst, cm.IfIndex, cm.NextHop, cm.MTU) } // Ancillary data socket options const ( ctlTrafficClass = iota // header field ctlHopLimit // header field ctlPacketInfo // inbound or outbound packet path ctlNextHop // nexthop ctlPathMTU // path mtu ctlMax ) // A ctlOpt represents a binding for ancillary data socket option. type ctlOpt struct { name int // option name, must be equal or greater than 1 length int // option length marshal func([]byte, *ControlMessage) []byte parse func(*ControlMessage, []byte) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/control_rfc2292_unix.go000066400000000000000000000030551264464372400255520ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin package ipv6 import ( "syscall" "unsafe" "golang.org/x/net/internal/iana" ) func marshal2292HopLimit(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIPv6 m.Type = sysIPV6_2292HOPLIMIT m.SetLen(syscall.CmsgLen(4)) if cm != nil { data := b[syscall.CmsgLen(0):] // TODO(mikio): fix potential misaligned memory access *(*int32)(unsafe.Pointer(&data[:4][0])) = int32(cm.HopLimit) } return b[syscall.CmsgSpace(4):] } func marshal2292PacketInfo(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIPv6 m.Type = sysIPV6_2292PKTINFO m.SetLen(syscall.CmsgLen(sysSizeofInet6Pktinfo)) if cm != nil { pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)])) if ip := cm.Src.To16(); ip != nil && ip.To4() == nil { copy(pi.Addr[:], ip) } if cm.IfIndex > 0 { pi.setIfindex(cm.IfIndex) } } return b[syscall.CmsgSpace(sysSizeofInet6Pktinfo):] } func marshal2292NextHop(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIPv6 m.Type = sysIPV6_2292NEXTHOP m.SetLen(syscall.CmsgLen(sysSizeofSockaddrInet6)) if cm != nil { sa := (*sysSockaddrInet6)(unsafe.Pointer(&b[syscall.CmsgLen(0)])) sa.setSockaddr(cm.NextHop, cm.IfIndex) } return b[syscall.CmsgSpace(sysSizeofSockaddrInet6):] } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/control_rfc3542_unix.go000066400000000000000000000056761264464372400255640ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin dragonfly freebsd linux netbsd openbsd package ipv6 import ( "syscall" "unsafe" "golang.org/x/net/internal/iana" ) func marshalTrafficClass(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIPv6 m.Type = sysIPV6_TCLASS m.SetLen(syscall.CmsgLen(4)) if cm != nil { data := b[syscall.CmsgLen(0):] // TODO(mikio): fix potential misaligned memory access *(*int32)(unsafe.Pointer(&data[:4][0])) = int32(cm.TrafficClass) } return b[syscall.CmsgSpace(4):] } func parseTrafficClass(cm *ControlMessage, b []byte) { // TODO(mikio): fix potential misaligned memory access cm.TrafficClass = int(*(*int32)(unsafe.Pointer(&b[:4][0]))) } func marshalHopLimit(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIPv6 m.Type = sysIPV6_HOPLIMIT m.SetLen(syscall.CmsgLen(4)) if cm != nil { data := b[syscall.CmsgLen(0):] // TODO(mikio): fix potential misaligned memory access *(*int32)(unsafe.Pointer(&data[:4][0])) = int32(cm.HopLimit) } return b[syscall.CmsgSpace(4):] } func parseHopLimit(cm *ControlMessage, b []byte) { // TODO(mikio): fix potential misaligned memory access cm.HopLimit = int(*(*int32)(unsafe.Pointer(&b[:4][0]))) } func marshalPacketInfo(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIPv6 m.Type = sysIPV6_PKTINFO m.SetLen(syscall.CmsgLen(sysSizeofInet6Pktinfo)) if cm != nil { pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[syscall.CmsgLen(0)])) if ip := cm.Src.To16(); ip != nil && ip.To4() == nil { copy(pi.Addr[:], ip) } if cm.IfIndex > 0 { pi.setIfindex(cm.IfIndex) } } return b[syscall.CmsgSpace(sysSizeofInet6Pktinfo):] } func parsePacketInfo(cm *ControlMessage, b []byte) { pi := (*sysInet6Pktinfo)(unsafe.Pointer(&b[0])) cm.Dst = pi.Addr[:] cm.IfIndex = int(pi.Ifindex) } func marshalNextHop(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIPv6 m.Type = sysIPV6_NEXTHOP m.SetLen(syscall.CmsgLen(sysSizeofSockaddrInet6)) if cm != nil { sa := (*sysSockaddrInet6)(unsafe.Pointer(&b[syscall.CmsgLen(0)])) sa.setSockaddr(cm.NextHop, cm.IfIndex) } return b[syscall.CmsgSpace(sysSizeofSockaddrInet6):] } func parseNextHop(cm *ControlMessage, b []byte) { } func marshalPathMTU(b []byte, cm *ControlMessage) []byte { m := (*syscall.Cmsghdr)(unsafe.Pointer(&b[0])) m.Level = iana.ProtocolIPv6 m.Type = sysIPV6_PATHMTU m.SetLen(syscall.CmsgLen(sysSizeofIPv6Mtuinfo)) return b[syscall.CmsgSpace(sysSizeofIPv6Mtuinfo):] } func parsePathMTU(cm *ControlMessage, b []byte) { mi := (*sysIPv6Mtuinfo)(unsafe.Pointer(&b[0])) cm.Dst = mi.Addr.Addr[:] cm.IfIndex = int(mi.Addr.Scope_id) cm.MTU = int(mi.Mtu) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/control_stub.go000066400000000000000000000010401264464372400243630ustar00rootroot00000000000000// Copyright 2013 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. // +build nacl plan9 solaris package ipv6 func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { return errOpNoSupport } func newControlMessage(opt *rawOpt) (oob []byte) { return nil } func parseControlMessage(b []byte) (*ControlMessage, error) { return nil, errOpNoSupport } func marshalControlMessage(cm *ControlMessage) (oob []byte) { return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/control_unix.go000066400000000000000000000104451264464372400244020ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin dragonfly freebsd linux netbsd openbsd package ipv6 import ( "os" "syscall" "golang.org/x/net/internal/iana" ) func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error { opt.Lock() defer opt.Unlock() if cf&FlagTrafficClass != 0 && sockOpts[ssoReceiveTrafficClass].name > 0 { if err := setInt(fd, &sockOpts[ssoReceiveTrafficClass], boolint(on)); err != nil { return err } if on { opt.set(FlagTrafficClass) } else { opt.clear(FlagTrafficClass) } } if cf&FlagHopLimit != 0 && sockOpts[ssoReceiveHopLimit].name > 0 { if err := setInt(fd, &sockOpts[ssoReceiveHopLimit], boolint(on)); err != nil { return err } if on { opt.set(FlagHopLimit) } else { opt.clear(FlagHopLimit) } } if cf&flagPacketInfo != 0 && sockOpts[ssoReceivePacketInfo].name > 0 { if err := setInt(fd, &sockOpts[ssoReceivePacketInfo], boolint(on)); err != nil { return err } if on { opt.set(cf & flagPacketInfo) } else { opt.clear(cf & flagPacketInfo) } } if cf&FlagPathMTU != 0 && sockOpts[ssoReceivePathMTU].name > 0 { if err := setInt(fd, &sockOpts[ssoReceivePathMTU], boolint(on)); err != nil { return err } if on { opt.set(FlagPathMTU) } else { opt.clear(FlagPathMTU) } } return nil } func newControlMessage(opt *rawOpt) (oob []byte) { opt.RLock() var l int if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 { l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length) } if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 { l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length) } if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 { l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length) } if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 { l += syscall.CmsgSpace(ctlOpts[ctlPathMTU].length) } if l > 0 { oob = make([]byte, l) b := oob if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 { b = ctlOpts[ctlTrafficClass].marshal(b, nil) } if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 { b = ctlOpts[ctlHopLimit].marshal(b, nil) } if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 { b = ctlOpts[ctlPacketInfo].marshal(b, nil) } if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 { b = ctlOpts[ctlPathMTU].marshal(b, nil) } } opt.RUnlock() return } func parseControlMessage(b []byte) (*ControlMessage, error) { if len(b) == 0 { return nil, nil } cmsgs, err := syscall.ParseSocketControlMessage(b) if err != nil { return nil, os.NewSyscallError("parse socket control message", err) } cm := &ControlMessage{} for _, m := range cmsgs { if m.Header.Level != iana.ProtocolIPv6 { continue } switch int(m.Header.Type) { case ctlOpts[ctlTrafficClass].name: ctlOpts[ctlTrafficClass].parse(cm, m.Data[:]) case ctlOpts[ctlHopLimit].name: ctlOpts[ctlHopLimit].parse(cm, m.Data[:]) case ctlOpts[ctlPacketInfo].name: ctlOpts[ctlPacketInfo].parse(cm, m.Data[:]) case ctlOpts[ctlPathMTU].name: ctlOpts[ctlPathMTU].parse(cm, m.Data[:]) } } return cm, nil } func marshalControlMessage(cm *ControlMessage) (oob []byte) { if cm == nil { return } var l int tclass := false if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 { tclass = true l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length) } hoplimit := false if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 { hoplimit = true l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length) } pktinfo := false if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) { pktinfo = true l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length) } nexthop := false if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil { nexthop = true l += syscall.CmsgSpace(ctlOpts[ctlNextHop].length) } if l > 0 { oob = make([]byte, l) b := oob if tclass { b = ctlOpts[ctlTrafficClass].marshal(b, cm) } if hoplimit { b = ctlOpts[ctlHopLimit].marshal(b, cm) } if pktinfo { b = ctlOpts[ctlPacketInfo].marshal(b, cm) } if nexthop { b = ctlOpts[ctlNextHop].marshal(b, cm) } } return } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/control_windows.go000066400000000000000000000012431264464372400251050ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import "syscall" func setControlMessage(fd syscall.Handle, opt *rawOpt, cf ControlFlags, on bool) error { // TODO(mikio): implement this return syscall.EWINDOWS } func newControlMessage(opt *rawOpt) (oob []byte) { // TODO(mikio): implement this return nil } func parseControlMessage(b []byte) (*ControlMessage, error) { // TODO(mikio): implement this return nil, syscall.EWINDOWS } func marshalControlMessage(cm *ControlMessage) (oob []byte) { // TODO(mikio): implement this return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/defs_darwin.go000066400000000000000000000063471264464372400241520ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in6_addr [16]byte /* in6_addr */ package ipv6 /* #define __APPLE_USE_RFC_3542 #include #include */ import "C" const ( sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP sysIPV6_PORTRANGE = C.IPV6_PORTRANGE sysICMP6_FILTER = C.ICMP6_FILTER sysIPV6_2292PKTINFO = C.IPV6_2292PKTINFO sysIPV6_2292HOPLIMIT = C.IPV6_2292HOPLIMIT sysIPV6_2292NEXTHOP = C.IPV6_2292NEXTHOP sysIPV6_2292HOPOPTS = C.IPV6_2292HOPOPTS sysIPV6_2292DSTOPTS = C.IPV6_2292DSTOPTS sysIPV6_2292RTHDR = C.IPV6_2292RTHDR sysIPV6_2292PKTOPTIONS = C.IPV6_2292PKTOPTIONS sysIPV6_CHECKSUM = C.IPV6_CHECKSUM sysIPV6_V6ONLY = C.IPV6_V6ONLY sysIPV6_IPSEC_POLICY = C.IPV6_IPSEC_POLICY sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS sysIPV6_TCLASS = C.IPV6_TCLASS sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU sysIPV6_PATHMTU = C.IPV6_PATHMTU sysIPV6_PKTINFO = C.IPV6_PKTINFO sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT sysIPV6_NEXTHOP = C.IPV6_NEXTHOP sysIPV6_HOPOPTS = C.IPV6_HOPOPTS sysIPV6_DSTOPTS = C.IPV6_DSTOPTS sysIPV6_RTHDR = C.IPV6_RTHDR sysIPV6_AUTOFLOWLABEL = C.IPV6_AUTOFLOWLABEL sysIPV6_DONTFRAG = C.IPV6_DONTFRAG sysIPV6_PREFER_TEMPADDR = C.IPV6_PREFER_TEMPADDR sysIPV6_MSFILTER = C.IPV6_MSFILTER sysMCAST_JOIN_GROUP = C.MCAST_JOIN_GROUP sysMCAST_LEAVE_GROUP = C.MCAST_LEAVE_GROUP sysMCAST_JOIN_SOURCE_GROUP = C.MCAST_JOIN_SOURCE_GROUP sysMCAST_LEAVE_SOURCE_GROUP = C.MCAST_LEAVE_SOURCE_GROUP sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE sysIPV6_BOUND_IF = C.IPV6_BOUND_IF sysIPV6_PORTRANGE_DEFAULT = C.IPV6_PORTRANGE_DEFAULT sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW sysSizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6 sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq sysSizeofGroupReq = C.sizeof_struct_group_req sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter ) type sysSockaddrStorage C.struct_sockaddr_storage type sysSockaddrInet6 C.struct_sockaddr_in6 type sysInet6Pktinfo C.struct_in6_pktinfo type sysIPv6Mtuinfo C.struct_ip6_mtuinfo type sysIPv6Mreq C.struct_ipv6_mreq type sysICMPv6Filter C.struct_icmp6_filter type sysGroupReq C.struct_group_req type sysGroupSourceReq C.struct_group_source_req golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/defs_dragonfly.go000066400000000000000000000043551264464372400246500ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in6_addr [16]byte /* in6_addr */ package ipv6 /* #include #include #include #include */ import "C" const ( sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP sysIPV6_PORTRANGE = C.IPV6_PORTRANGE sysICMP6_FILTER = C.ICMP6_FILTER sysIPV6_CHECKSUM = C.IPV6_CHECKSUM sysIPV6_V6ONLY = C.IPV6_V6ONLY sysIPV6_IPSEC_POLICY = C.IPV6_IPSEC_POLICY sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU sysIPV6_PATHMTU = C.IPV6_PATHMTU sysIPV6_PKTINFO = C.IPV6_PKTINFO sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT sysIPV6_NEXTHOP = C.IPV6_NEXTHOP sysIPV6_HOPOPTS = C.IPV6_HOPOPTS sysIPV6_DSTOPTS = C.IPV6_DSTOPTS sysIPV6_RTHDR = C.IPV6_RTHDR sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS sysIPV6_AUTOFLOWLABEL = C.IPV6_AUTOFLOWLABEL sysIPV6_TCLASS = C.IPV6_TCLASS sysIPV6_DONTFRAG = C.IPV6_DONTFRAG sysIPV6_PREFER_TEMPADDR = C.IPV6_PREFER_TEMPADDR sysIPV6_PORTRANGE_DEFAULT = C.IPV6_PORTRANGE_DEFAULT sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6 sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter ) type sysSockaddrInet6 C.struct_sockaddr_in6 type sysInet6Pktinfo C.struct_in6_pktinfo type sysIPv6Mtuinfo C.struct_ip6_mtuinfo type sysIPv6Mreq C.struct_ipv6_mreq type sysICMPv6Filter C.struct_icmp6_filter golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/defs_freebsd.go000066400000000000000000000056751264464372400243030ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in6_addr [16]byte /* in6_addr */ package ipv6 /* #include #include #include #include */ import "C" const ( sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP sysIPV6_PORTRANGE = C.IPV6_PORTRANGE sysICMP6_FILTER = C.ICMP6_FILTER sysIPV6_CHECKSUM = C.IPV6_CHECKSUM sysIPV6_V6ONLY = C.IPV6_V6ONLY sysIPV6_IPSEC_POLICY = C.IPV6_IPSEC_POLICY sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU sysIPV6_PATHMTU = C.IPV6_PATHMTU sysIPV6_PKTINFO = C.IPV6_PKTINFO sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT sysIPV6_NEXTHOP = C.IPV6_NEXTHOP sysIPV6_HOPOPTS = C.IPV6_HOPOPTS sysIPV6_DSTOPTS = C.IPV6_DSTOPTS sysIPV6_RTHDR = C.IPV6_RTHDR sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS sysIPV6_AUTOFLOWLABEL = C.IPV6_AUTOFLOWLABEL sysIPV6_TCLASS = C.IPV6_TCLASS sysIPV6_DONTFRAG = C.IPV6_DONTFRAG sysIPV6_PREFER_TEMPADDR = C.IPV6_PREFER_TEMPADDR sysIPV6_BINDANY = C.IPV6_BINDANY sysIPV6_MSFILTER = C.IPV6_MSFILTER sysMCAST_JOIN_GROUP = C.MCAST_JOIN_GROUP sysMCAST_LEAVE_GROUP = C.MCAST_LEAVE_GROUP sysMCAST_JOIN_SOURCE_GROUP = C.MCAST_JOIN_SOURCE_GROUP sysMCAST_LEAVE_SOURCE_GROUP = C.MCAST_LEAVE_SOURCE_GROUP sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE sysIPV6_PORTRANGE_DEFAULT = C.IPV6_PORTRANGE_DEFAULT sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW sysSizeofSockaddrStorage = C.sizeof_struct_sockaddr_storage sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6 sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq sysSizeofGroupReq = C.sizeof_struct_group_req sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter ) type sysSockaddrStorage C.struct_sockaddr_storage type sysSockaddrInet6 C.struct_sockaddr_in6 type sysInet6Pktinfo C.struct_in6_pktinfo type sysIPv6Mtuinfo C.struct_ip6_mtuinfo type sysIPv6Mreq C.struct_ipv6_mreq type sysGroupReq C.struct_group_req type sysGroupSourceReq C.struct_group_source_req type sysICMPv6Filter C.struct_icmp6_filter golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/defs_linux.go000066400000000000000000000115131264464372400240140ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in6_addr [16]byte /* in6_addr */ package ipv6 /* #include #include #include #include */ import "C" const ( sysIPV6_ADDRFORM = C.IPV6_ADDRFORM sysIPV6_2292PKTINFO = C.IPV6_2292PKTINFO sysIPV6_2292HOPOPTS = C.IPV6_2292HOPOPTS sysIPV6_2292DSTOPTS = C.IPV6_2292DSTOPTS sysIPV6_2292RTHDR = C.IPV6_2292RTHDR sysIPV6_2292PKTOPTIONS = C.IPV6_2292PKTOPTIONS sysIPV6_CHECKSUM = C.IPV6_CHECKSUM sysIPV6_2292HOPLIMIT = C.IPV6_2292HOPLIMIT sysIPV6_NEXTHOP = C.IPV6_NEXTHOP sysIPV6_FLOWINFO = C.IPV6_FLOWINFO sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP sysIPV6_ADD_MEMBERSHIP = C.IPV6_ADD_MEMBERSHIP sysIPV6_DROP_MEMBERSHIP = C.IPV6_DROP_MEMBERSHIP sysMCAST_JOIN_GROUP = C.MCAST_JOIN_GROUP sysMCAST_LEAVE_GROUP = C.MCAST_LEAVE_GROUP sysMCAST_JOIN_SOURCE_GROUP = C.MCAST_JOIN_SOURCE_GROUP sysMCAST_LEAVE_SOURCE_GROUP = C.MCAST_LEAVE_SOURCE_GROUP sysMCAST_BLOCK_SOURCE = C.MCAST_BLOCK_SOURCE sysMCAST_UNBLOCK_SOURCE = C.MCAST_UNBLOCK_SOURCE sysMCAST_MSFILTER = C.MCAST_MSFILTER sysIPV6_ROUTER_ALERT = C.IPV6_ROUTER_ALERT sysIPV6_MTU_DISCOVER = C.IPV6_MTU_DISCOVER sysIPV6_MTU = C.IPV6_MTU sysIPV6_RECVERR = C.IPV6_RECVERR sysIPV6_V6ONLY = C.IPV6_V6ONLY sysIPV6_JOIN_ANYCAST = C.IPV6_JOIN_ANYCAST sysIPV6_LEAVE_ANYCAST = C.IPV6_LEAVE_ANYCAST //sysIPV6_PMTUDISC_DONT = C.IPV6_PMTUDISC_DONT //sysIPV6_PMTUDISC_WANT = C.IPV6_PMTUDISC_WANT //sysIPV6_PMTUDISC_DO = C.IPV6_PMTUDISC_DO //sysIPV6_PMTUDISC_PROBE = C.IPV6_PMTUDISC_PROBE //sysIPV6_PMTUDISC_INTERFACE = C.IPV6_PMTUDISC_INTERFACE //sysIPV6_PMTUDISC_OMIT = C.IPV6_PMTUDISC_OMIT sysIPV6_FLOWLABEL_MGR = C.IPV6_FLOWLABEL_MGR sysIPV6_FLOWINFO_SEND = C.IPV6_FLOWINFO_SEND sysIPV6_IPSEC_POLICY = C.IPV6_IPSEC_POLICY sysIPV6_XFRM_POLICY = C.IPV6_XFRM_POLICY sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO sysIPV6_PKTINFO = C.IPV6_PKTINFO sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS sysIPV6_HOPOPTS = C.IPV6_HOPOPTS sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR sysIPV6_RTHDR = C.IPV6_RTHDR sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS sysIPV6_DSTOPTS = C.IPV6_DSTOPTS sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU sysIPV6_PATHMTU = C.IPV6_PATHMTU sysIPV6_DONTFRAG = C.IPV6_DONTFRAG sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS sysIPV6_TCLASS = C.IPV6_TCLASS sysIPV6_ADDR_PREFERENCES = C.IPV6_ADDR_PREFERENCES sysIPV6_PREFER_SRC_TMP = C.IPV6_PREFER_SRC_TMP sysIPV6_PREFER_SRC_PUBLIC = C.IPV6_PREFER_SRC_PUBLIC sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = C.IPV6_PREFER_SRC_PUBTMP_DEFAULT sysIPV6_PREFER_SRC_COA = C.IPV6_PREFER_SRC_COA sysIPV6_PREFER_SRC_HOME = C.IPV6_PREFER_SRC_HOME sysIPV6_PREFER_SRC_CGA = C.IPV6_PREFER_SRC_CGA sysIPV6_PREFER_SRC_NONCGA = C.IPV6_PREFER_SRC_NONCGA sysIPV6_MINHOPCOUNT = C.IPV6_MINHOPCOUNT sysIPV6_ORIGDSTADDR = C.IPV6_ORIGDSTADDR sysIPV6_RECVORIGDSTADDR = C.IPV6_RECVORIGDSTADDR sysIPV6_TRANSPARENT = C.IPV6_TRANSPARENT sysIPV6_UNICAST_IF = C.IPV6_UNICAST_IF sysICMPV6_FILTER = C.ICMPV6_FILTER sysICMPV6_FILTER_BLOCK = C.ICMPV6_FILTER_BLOCK sysICMPV6_FILTER_PASS = C.ICMPV6_FILTER_PASS sysICMPV6_FILTER_BLOCKOTHERS = C.ICMPV6_FILTER_BLOCKOTHERS sysICMPV6_FILTER_PASSONLY = C.ICMPV6_FILTER_PASSONLY sysSizeofKernelSockaddrStorage = C.sizeof_struct___kernel_sockaddr_storage sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6 sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo sysSizeofIPv6FlowlabelReq = C.sizeof_struct_in6_flowlabel_req sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq sysSizeofGroupReq = C.sizeof_struct_group_req sysSizeofGroupSourceReq = C.sizeof_struct_group_source_req sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter ) type sysKernelSockaddrStorage C.struct___kernel_sockaddr_storage type sysSockaddrInet6 C.struct_sockaddr_in6 type sysInet6Pktinfo C.struct_in6_pktinfo type sysIPv6Mtuinfo C.struct_ip6_mtuinfo type sysIPv6FlowlabelReq C.struct_in6_flowlabel_req type sysIPv6Mreq C.struct_ipv6_mreq type sysGroupReq C.struct_group_req type sysGroupSourceReq C.struct_group_source_req type sysICMPv6Filter C.struct_icmp6_filter golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/defs_netbsd.go000066400000000000000000000042171264464372400241370ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in6_addr [16]byte /* in6_addr */ package ipv6 /* #include #include #include #include */ import "C" const ( sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP sysIPV6_PORTRANGE = C.IPV6_PORTRANGE sysICMP6_FILTER = C.ICMP6_FILTER sysIPV6_CHECKSUM = C.IPV6_CHECKSUM sysIPV6_V6ONLY = C.IPV6_V6ONLY sysIPV6_IPSEC_POLICY = C.IPV6_IPSEC_POLICY sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU sysIPV6_PATHMTU = C.IPV6_PATHMTU sysIPV6_PKTINFO = C.IPV6_PKTINFO sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT sysIPV6_NEXTHOP = C.IPV6_NEXTHOP sysIPV6_HOPOPTS = C.IPV6_HOPOPTS sysIPV6_DSTOPTS = C.IPV6_DSTOPTS sysIPV6_RTHDR = C.IPV6_RTHDR sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS sysIPV6_TCLASS = C.IPV6_TCLASS sysIPV6_DONTFRAG = C.IPV6_DONTFRAG sysIPV6_PORTRANGE_DEFAULT = C.IPV6_PORTRANGE_DEFAULT sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6 sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter ) type sysSockaddrInet6 C.struct_sockaddr_in6 type sysInet6Pktinfo C.struct_in6_pktinfo type sysIPv6Mtuinfo C.struct_ip6_mtuinfo type sysIPv6Mreq C.struct_ipv6_mreq type sysICMPv6Filter C.struct_icmp6_filter golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/defs_openbsd.go000066400000000000000000000047111264464372400243110ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in6_addr [16]byte /* in6_addr */ package ipv6 /* #include #include #include #include */ import "C" const ( sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP sysIPV6_PORTRANGE = C.IPV6_PORTRANGE sysICMP6_FILTER = C.ICMP6_FILTER sysIPV6_CHECKSUM = C.IPV6_CHECKSUM sysIPV6_V6ONLY = C.IPV6_V6ONLY sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU sysIPV6_PATHMTU = C.IPV6_PATHMTU sysIPV6_PKTINFO = C.IPV6_PKTINFO sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT sysIPV6_NEXTHOP = C.IPV6_NEXTHOP sysIPV6_HOPOPTS = C.IPV6_HOPOPTS sysIPV6_DSTOPTS = C.IPV6_DSTOPTS sysIPV6_RTHDR = C.IPV6_RTHDR sysIPV6_AUTH_LEVEL = C.IPV6_AUTH_LEVEL sysIPV6_ESP_TRANS_LEVEL = C.IPV6_ESP_TRANS_LEVEL sysIPV6_ESP_NETWORK_LEVEL = C.IPV6_ESP_NETWORK_LEVEL sysIPSEC6_OUTSA = C.IPSEC6_OUTSA sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS sysIPV6_AUTOFLOWLABEL = C.IPV6_AUTOFLOWLABEL sysIPV6_IPCOMP_LEVEL = C.IPV6_IPCOMP_LEVEL sysIPV6_TCLASS = C.IPV6_TCLASS sysIPV6_DONTFRAG = C.IPV6_DONTFRAG sysIPV6_PIPEX = C.IPV6_PIPEX sysIPV6_RTABLE = C.IPV6_RTABLE sysIPV6_PORTRANGE_DEFAULT = C.IPV6_PORTRANGE_DEFAULT sysIPV6_PORTRANGE_HIGH = C.IPV6_PORTRANGE_HIGH sysIPV6_PORTRANGE_LOW = C.IPV6_PORTRANGE_LOW sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6 sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter ) type sysSockaddrInet6 C.struct_sockaddr_in6 type sysInet6Pktinfo C.struct_in6_pktinfo type sysIPv6Mtuinfo C.struct_ip6_mtuinfo type sysIPv6Mreq C.struct_ipv6_mreq type sysICMPv6Filter C.struct_icmp6_filter golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/defs_solaris.go000066400000000000000000000056031264464372400243340ustar00rootroot00000000000000// Copyright 2014 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. // +build ignore // +godefs map struct_in6_addr [16]byte /* in6_addr */ package ipv6 /* #include #include */ import "C" const ( sysIPV6_UNICAST_HOPS = C.IPV6_UNICAST_HOPS sysIPV6_MULTICAST_IF = C.IPV6_MULTICAST_IF sysIPV6_MULTICAST_HOPS = C.IPV6_MULTICAST_HOPS sysIPV6_MULTICAST_LOOP = C.IPV6_MULTICAST_LOOP sysIPV6_JOIN_GROUP = C.IPV6_JOIN_GROUP sysIPV6_LEAVE_GROUP = C.IPV6_LEAVE_GROUP sysIPV6_PKTINFO = C.IPV6_PKTINFO sysIPV6_HOPLIMIT = C.IPV6_HOPLIMIT sysIPV6_NEXTHOP = C.IPV6_NEXTHOP sysIPV6_HOPOPTS = C.IPV6_HOPOPTS sysIPV6_DSTOPTS = C.IPV6_DSTOPTS sysIPV6_RTHDR = C.IPV6_RTHDR sysIPV6_RTHDRDSTOPTS = C.IPV6_RTHDRDSTOPTS sysIPV6_RECVPKTINFO = C.IPV6_RECVPKTINFO sysIPV6_RECVHOPLIMIT = C.IPV6_RECVHOPLIMIT sysIPV6_RECVHOPOPTS = C.IPV6_RECVHOPOPTS sysIPV6_RECVRTHDR = C.IPV6_RECVRTHDR sysIPV6_RECVRTHDRDSTOPTS = C.IPV6_RECVRTHDRDSTOPTS sysIPV6_CHECKSUM = C.IPV6_CHECKSUM sysIPV6_RECVTCLASS = C.IPV6_RECVTCLASS sysIPV6_USE_MIN_MTU = C.IPV6_USE_MIN_MTU sysIPV6_DONTFRAG = C.IPV6_DONTFRAG sysIPV6_SEC_OPT = C.IPV6_SEC_OPT sysIPV6_SRC_PREFERENCES = C.IPV6_SRC_PREFERENCES sysIPV6_RECVPATHMTU = C.IPV6_RECVPATHMTU sysIPV6_PATHMTU = C.IPV6_PATHMTU sysIPV6_TCLASS = C.IPV6_TCLASS sysIPV6_V6ONLY = C.IPV6_V6ONLY sysIPV6_RECVDSTOPTS = C.IPV6_RECVDSTOPTS sysIPV6_PREFER_SRC_HOME = C.IPV6_PREFER_SRC_HOME sysIPV6_PREFER_SRC_COA = C.IPV6_PREFER_SRC_COA sysIPV6_PREFER_SRC_PUBLIC = C.IPV6_PREFER_SRC_PUBLIC sysIPV6_PREFER_SRC_TMP = C.IPV6_PREFER_SRC_TMP sysIPV6_PREFER_SRC_NONCGA = C.IPV6_PREFER_SRC_NONCGA sysIPV6_PREFER_SRC_CGA = C.IPV6_PREFER_SRC_CGA sysIPV6_PREFER_SRC_MIPMASK = C.IPV6_PREFER_SRC_MIPMASK sysIPV6_PREFER_SRC_MIPDEFAULT = C.IPV6_PREFER_SRC_MIPDEFAULT sysIPV6_PREFER_SRC_TMPMASK = C.IPV6_PREFER_SRC_TMPMASK sysIPV6_PREFER_SRC_TMPDEFAULT = C.IPV6_PREFER_SRC_TMPDEFAULT sysIPV6_PREFER_SRC_CGAMASK = C.IPV6_PREFER_SRC_CGAMASK sysIPV6_PREFER_SRC_CGADEFAULT = C.IPV6_PREFER_SRC_CGADEFAULT sysIPV6_PREFER_SRC_MASK = C.IPV6_PREFER_SRC_MASK sysIPV6_PREFER_SRC_DEFAULT = C.IPV6_PREFER_SRC_DEFAULT sysIPV6_BOUND_IF = C.IPV6_BOUND_IF sysIPV6_UNSPEC_SRC = C.IPV6_UNSPEC_SRC sysICMP6_FILTER = C.ICMP6_FILTER sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6 sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo sysSizeofIPv6Mtuinfo = C.sizeof_struct_ip6_mtuinfo sysSizeofIPv6Mreq = C.sizeof_struct_ipv6_mreq sysSizeofICMPv6Filter = C.sizeof_struct_icmp6_filter ) type sysSockaddrInet6 C.struct_sockaddr_in6 type sysInet6Pktinfo C.struct_in6_pktinfo type sysIPv6Mtuinfo C.struct_ip6_mtuinfo type sysIPv6Mreq C.struct_ipv6_mreq type sysICMPv6Filter C.struct_icmp6_filter golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/dgramopt_posix.go000066400000000000000000000164151264464372400247210ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin dragonfly freebsd linux netbsd openbsd windows package ipv6 import ( "net" "syscall" ) // MulticastHopLimit returns the hop limit field value for outgoing // multicast packets. func (c *dgramOpt) MulticastHopLimit() (int, error) { if !c.ok() { return 0, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return 0, err } return getInt(fd, &sockOpts[ssoMulticastHopLimit]) } // SetMulticastHopLimit sets the hop limit field value for future // outgoing multicast packets. func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setInt(fd, &sockOpts[ssoMulticastHopLimit], hoplim) } // MulticastInterface returns the default interface for multicast // packet transmissions. func (c *dgramOpt) MulticastInterface() (*net.Interface, error) { if !c.ok() { return nil, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return nil, err } return getInterface(fd, &sockOpts[ssoMulticastInterface]) } // SetMulticastInterface sets the default interface for future // multicast packet transmissions. func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setInterface(fd, &sockOpts[ssoMulticastInterface], ifi) } // MulticastLoopback reports whether transmitted multicast packets // should be copied and send back to the originator. func (c *dgramOpt) MulticastLoopback() (bool, error) { if !c.ok() { return false, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return false, err } on, err := getInt(fd, &sockOpts[ssoMulticastLoopback]) if err != nil { return false, err } return on == 1, nil } // SetMulticastLoopback sets whether transmitted multicast packets // should be copied and send back to the originator. func (c *dgramOpt) SetMulticastLoopback(on bool) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setInt(fd, &sockOpts[ssoMulticastLoopback], boolint(on)) } // JoinGroup joins the group address group on the interface ifi. // By default all sources that can cast data to group are accepted. // It's possible to mute and unmute data transmission from a specific // source by using ExcludeSourceSpecificGroup and // IncludeSourceSpecificGroup. // JoinGroup uses the system assigned multicast interface when ifi is // nil, although this is not recommended because the assignment // depends on platforms and sometimes it might require routing // configuration. func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP16(group) if grp == nil { return errMissingAddress } return setGroup(fd, &sockOpts[ssoJoinGroup], ifi, grp) } // LeaveGroup leaves the group address group on the interface ifi // regardless of whether the group is any-source group or // source-specific group. func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP16(group) if grp == nil { return errMissingAddress } return setGroup(fd, &sockOpts[ssoLeaveGroup], ifi, grp) } // JoinSourceSpecificGroup joins the source-specific group comprising // group and source on the interface ifi. // JoinSourceSpecificGroup uses the system assigned multicast // interface when ifi is nil, although this is not recommended because // the assignment depends on platforms and sometimes it might require // routing configuration. func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP16(group) if grp == nil { return errMissingAddress } src := netAddrToIP16(source) if src == nil { return errMissingAddress } return setSourceGroup(fd, &sockOpts[ssoJoinSourceGroup], ifi, grp, src) } // LeaveSourceSpecificGroup leaves the source-specific group on the // interface ifi. func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP16(group) if grp == nil { return errMissingAddress } src := netAddrToIP16(source) if src == nil { return errMissingAddress } return setSourceGroup(fd, &sockOpts[ssoLeaveSourceGroup], ifi, grp, src) } // ExcludeSourceSpecificGroup excludes the source-specific group from // the already joined any-source groups by JoinGroup on the interface // ifi. func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP16(group) if grp == nil { return errMissingAddress } src := netAddrToIP16(source) if src == nil { return errMissingAddress } return setSourceGroup(fd, &sockOpts[ssoBlockSourceGroup], ifi, grp, src) } // IncludeSourceSpecificGroup includes the excluded source-specific // group by ExcludeSourceSpecificGroup again on the interface ifi. func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } grp := netAddrToIP16(group) if grp == nil { return errMissingAddress } src := netAddrToIP16(source) if src == nil { return errMissingAddress } return setSourceGroup(fd, &sockOpts[ssoUnblockSourceGroup], ifi, grp, src) } // Checksum reports whether the kernel will compute, store or verify a // checksum for both incoming and outgoing packets. If on is true, it // returns an offset in bytes into the data of where the checksum // field is located. func (c *dgramOpt) Checksum() (on bool, offset int, err error) { if !c.ok() { return false, 0, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return false, 0, err } offset, err = getInt(fd, &sockOpts[ssoChecksum]) if err != nil { return false, 0, err } if offset < 0 { return false, 0, nil } return true, offset, nil } // SetChecksum enables the kernel checksum processing. If on is ture, // the offset should be an offset in bytes into the data of where the // checksum field is located. func (c *dgramOpt) SetChecksum(on bool, offset int) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } if !on { offset = -1 } return setInt(fd, &sockOpts[ssoChecksum], offset) } // ICMPFilter returns an ICMP filter. func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) { if !c.ok() { return nil, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return nil, err } return getICMPFilter(fd, &sockOpts[ssoICMPFilter]) } // SetICMPFilter deploys the ICMP filter. func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setICMPFilter(fd, &sockOpts[ssoICMPFilter], f) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/dgramopt_stub.go000066400000000000000000000102321264464372400245230ustar00rootroot00000000000000// Copyright 2013 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. // +build nacl plan9 solaris package ipv6 import "net" // MulticastHopLimit returns the hop limit field value for outgoing // multicast packets. func (c *dgramOpt) MulticastHopLimit() (int, error) { return 0, errOpNoSupport } // SetMulticastHopLimit sets the hop limit field value for future // outgoing multicast packets. func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error { return errOpNoSupport } // MulticastInterface returns the default interface for multicast // packet transmissions. func (c *dgramOpt) MulticastInterface() (*net.Interface, error) { return nil, errOpNoSupport } // SetMulticastInterface sets the default interface for future // multicast packet transmissions. func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error { return errOpNoSupport } // MulticastLoopback reports whether transmitted multicast packets // should be copied and send back to the originator. func (c *dgramOpt) MulticastLoopback() (bool, error) { return false, errOpNoSupport } // SetMulticastLoopback sets whether transmitted multicast packets // should be copied and send back to the originator. func (c *dgramOpt) SetMulticastLoopback(on bool) error { return errOpNoSupport } // JoinGroup joins the group address group on the interface ifi. // By default all sources that can cast data to group are accepted. // It's possible to mute and unmute data transmission from a specific // source by using ExcludeSourceSpecificGroup and // IncludeSourceSpecificGroup. // JoinGroup uses the system assigned multicast interface when ifi is // nil, although this is not recommended because the assignment // depends on platforms and sometimes it might require routing // configuration. func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error { return errOpNoSupport } // LeaveGroup leaves the group address group on the interface ifi // regardless of whether the group is any-source group or // source-specific group. func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error { return errOpNoSupport } // JoinSourceSpecificGroup joins the source-specific group comprising // group and source on the interface ifi. // JoinSourceSpecificGroup uses the system assigned multicast // interface when ifi is nil, although this is not recommended because // the assignment depends on platforms and sometimes it might require // routing configuration. func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { return errOpNoSupport } // LeaveSourceSpecificGroup leaves the source-specific group on the // interface ifi. func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { return errOpNoSupport } // ExcludeSourceSpecificGroup excludes the source-specific group from // the already joined any-source groups by JoinGroup on the interface // ifi. func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { return errOpNoSupport } // IncludeSourceSpecificGroup includes the excluded source-specific // group by ExcludeSourceSpecificGroup again on the interface ifi. func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error { return errOpNoSupport } // Checksum reports whether the kernel will compute, store or verify a // checksum for both incoming and outgoing packets. If on is true, it // returns an offset in bytes into the data of where the checksum // field is located. func (c *dgramOpt) Checksum() (on bool, offset int, err error) { return false, 0, errOpNoSupport } // SetChecksum enables the kernel checksum processing. If on is ture, // the offset should be an offset in bytes into the data of where the // checksum field is located. func (c *dgramOpt) SetChecksum(on bool, offset int) error { return errOpNoSupport } // ICMPFilter returns an ICMP filter. func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) { return nil, errOpNoSupport } // SetICMPFilter deploys the ICMP filter. func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error { return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/doc.go000066400000000000000000000172511264464372400224260ustar00rootroot00000000000000// Copyright 2013 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 ipv6 implements IP-level socket options for the Internet // Protocol version 6. // // The package provides IP-level socket options that allow // manipulation of IPv6 facilities. // // The IPv6 protocol is defined in RFC 2460. // Basic and advanced socket interface extensions are defined in RFC // 3493 and RFC 3542. // Socket interface extensions for multicast source filters are // defined in RFC 3678. // MLDv1 and MLDv2 are defined in RFC 2710 and RFC 3810. // Source-specific multicast is defined in RFC 4607. // // // Unicasting // // The options for unicasting are available for net.TCPConn, // net.UDPConn and net.IPConn which are created as network connections // that use the IPv6 transport. When a single TCP connection carrying // a data flow of multiple packets needs to indicate the flow is // important, ipv6.Conn is used to set the traffic class field on the // IPv6 header for each packet. // // ln, err := net.Listen("tcp6", "[::]:1024") // if err != nil { // // error handling // } // defer ln.Close() // for { // c, err := ln.Accept() // if err != nil { // // error handling // } // go func(c net.Conn) { // defer c.Close() // // The outgoing packets will be labeled DiffServ assured forwarding // class 1 low drop precedence, known as AF11 packets. // // if err := ipv6.NewConn(c).SetTrafficClass(0x28); err != nil { // // error handling // } // if _, err := c.Write(data); err != nil { // // error handling // } // }(c) // } // // // Multicasting // // The options for multicasting are available for net.UDPConn and // net.IPconn which are created as network connections that use the // IPv6 transport. A few network facilities must be prepared before // you begin multicasting, at a minimum joining network interfaces and // multicast groups. // // en0, err := net.InterfaceByName("en0") // if err != nil { // // error handling // } // en1, err := net.InterfaceByIndex(911) // if err != nil { // // error handling // } // group := net.ParseIP("ff02::114") // // First, an application listens to an appropriate address with an // appropriate service port. // // c, err := net.ListenPacket("udp6", "[::]:1024") // if err != nil { // // error handling // } // defer c.Close() // // Second, the application joins multicast groups, starts listening to // the groups on the specified network interfaces. Note that the // service port for transport layer protocol does not matter with this // operation as joining groups affects only network and link layer // protocols, such as IPv6 and Ethernet. // // p := ipv6.NewPacketConn(c) // if err := p.JoinGroup(en0, &net.UDPAddr{IP: group}); err != nil { // // error handling // } // if err := p.JoinGroup(en1, &net.UDPAddr{IP: group}); err != nil { // // error handling // } // // The application might set per packet control message transmissions // between the protocol stack within the kernel. When the application // needs a destination address on an incoming packet, // SetControlMessage of ipv6.PacketConn is used to enable control // message transmissons. // // if err := p.SetControlMessage(ipv6.FlagDst, true); err != nil { // // error handling // } // // The application could identify whether the received packets are // of interest by using the control message that contains the // destination address of the received packet. // // b := make([]byte, 1500) // for { // n, rcm, src, err := p.ReadFrom(b) // if err != nil { // // error handling // } // if rcm.Dst.IsMulticast() { // if rcm.Dst.Equal(group) { // // joined group, do something // } else { // // unknown group, discard // continue // } // } // // The application can also send both unicast and multicast packets. // // p.SetTrafficClass(0x0) // p.SetHopLimit(16) // if _, err := p.WriteTo(data[:n], nil, src); err != nil { // // error handling // } // dst := &net.UDPAddr{IP: group, Port: 1024} // wcm := ipv6.ControlMessage{TrafficClass: 0xe0, HopLimit: 1} // for _, ifi := range []*net.Interface{en0, en1} { // wcm.IfIndex = ifi.Index // if _, err := p.WriteTo(data[:n], &wcm, dst); err != nil { // // error handling // } // } // } // // // More multicasting // // An application that uses PacketConn may join multiple multicast // groups. For example, a UDP listener with port 1024 might join two // different groups across over two different network interfaces by // using: // // c, err := net.ListenPacket("udp6", "[::]:1024") // if err != nil { // // error handling // } // defer c.Close() // p := ipv6.NewPacketConn(c) // if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::1:114")}); err != nil { // // error handling // } // if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil { // // error handling // } // if err := p.JoinGroup(en1, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil { // // error handling // } // // It is possible for multiple UDP listeners that listen on the same // UDP port to join the same multicast group. The net package will // provide a socket that listens to a wildcard address with reusable // UDP port when an appropriate multicast address prefix is passed to // the net.ListenPacket or net.ListenUDP. // // c1, err := net.ListenPacket("udp6", "[ff02::]:1024") // if err != nil { // // error handling // } // defer c1.Close() // c2, err := net.ListenPacket("udp6", "[ff02::]:1024") // if err != nil { // // error handling // } // defer c2.Close() // p1 := ipv6.NewPacketConn(c1) // if err := p1.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil { // // error handling // } // p2 := ipv6.NewPacketConn(c2) // if err := p2.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil { // // error handling // } // // Also it is possible for the application to leave or rejoin a // multicast group on the network interface. // // if err := p.LeaveGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil { // // error handling // } // if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff01::114")}); err != nil { // // error handling // } // // // Source-specific multicasting // // An application that uses PacketConn on MLDv2 supported platform is // able to join source-specific multicast groups. // The application may use JoinSourceSpecificGroup and // LeaveSourceSpecificGroup for the operation known as "include" mode, // // ssmgroup := net.UDPAddr{IP: net.ParseIP("ff32::8000:9")} // ssmsource := net.UDPAddr{IP: net.ParseIP("fe80::cafe")} // if err := p.JoinSourceSpecificGroup(en0, &ssmgroup, &ssmsource); err != nil { // // error handling // } // if err := p.LeaveSourceSpecificGroup(en0, &ssmgroup, &ssmsource); err != nil { // // error handling // } // // or JoinGroup, ExcludeSourceSpecificGroup, // IncludeSourceSpecificGroup and LeaveGroup for the operation known // as "exclude" mode. // // exclsource := net.UDPAddr{IP: net.ParseIP("fe80::dead")} // if err := p.JoinGroup(en0, &ssmgroup); err != nil { // // error handling // } // if err := p.ExcludeSourceSpecificGroup(en0, &ssmgroup, &exclsource); err != nil { // // error handling // } // if err := p.LeaveGroup(en0, &ssmgroup); err != nil { // // error handling // } // // Note that it depends on each platform implementation what happens // when an application which runs on MLDv2 unsupported platform uses // JoinSourceSpecificGroup and LeaveSourceSpecificGroup. // In general the platform tries to fall back to conversations using // MLDv1 and starts to listen to multicast traffic. // In the fallback case, ExcludeSourceSpecificGroup and // IncludeSourceSpecificGroup may return an error. package ipv6 // import "golang.org/x/net/ipv6" golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/endpoint.go000066400000000000000000000057021264464372400234770ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import ( "net" "syscall" "time" ) // A Conn represents a network endpoint that uses IPv6 transport. // It allows to set basic IP-level socket options such as traffic // class and hop limit. type Conn struct { genericOpt } type genericOpt struct { net.Conn } func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil } // PathMTU returns a path MTU value for the destination associated // with the endpoint. func (c *Conn) PathMTU() (int, error) { if !c.genericOpt.ok() { return 0, syscall.EINVAL } fd, err := c.genericOpt.sysfd() if err != nil { return 0, err } _, mtu, err := getMTUInfo(fd, &sockOpts[ssoPathMTU]) if err != nil { return 0, err } return mtu, nil } // NewConn returns a new Conn. func NewConn(c net.Conn) *Conn { return &Conn{ genericOpt: genericOpt{Conn: c}, } } // A PacketConn represents a packet network endpoint that uses IPv6 // transport. It is used to control several IP-level socket options // including IPv6 header manipulation. It also provides datagram // based network I/O methods specific to the IPv6 and higher layer // protocols such as OSPF, GRE, and UDP. type PacketConn struct { genericOpt dgramOpt payloadHandler } type dgramOpt struct { net.PacketConn } func (c *dgramOpt) ok() bool { return c != nil && c.PacketConn != nil } // SetControlMessage allows to receive the per packet basis IP-level // socket options. func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error { if !c.payloadHandler.ok() { return syscall.EINVAL } fd, err := c.payloadHandler.sysfd() if err != nil { return err } return setControlMessage(fd, &c.payloadHandler.rawOpt, cf, on) } // SetDeadline sets the read and write deadlines associated with the // endpoint. func (c *PacketConn) SetDeadline(t time.Time) error { if !c.payloadHandler.ok() { return syscall.EINVAL } return c.payloadHandler.SetDeadline(t) } // SetReadDeadline sets the read deadline associated with the // endpoint. func (c *PacketConn) SetReadDeadline(t time.Time) error { if !c.payloadHandler.ok() { return syscall.EINVAL } return c.payloadHandler.SetReadDeadline(t) } // SetWriteDeadline sets the write deadline associated with the // endpoint. func (c *PacketConn) SetWriteDeadline(t time.Time) error { if !c.payloadHandler.ok() { return syscall.EINVAL } return c.payloadHandler.SetWriteDeadline(t) } // Close closes the endpoint. func (c *PacketConn) Close() error { if !c.payloadHandler.ok() { return syscall.EINVAL } return c.payloadHandler.Close() } // NewPacketConn returns a new PacketConn using c as its underlying // transport. func NewPacketConn(c net.PacketConn) *PacketConn { return &PacketConn{ genericOpt: genericOpt{Conn: c.(net.Conn)}, dgramOpt: dgramOpt{PacketConn: c}, payloadHandler: payloadHandler{PacketConn: c}, } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/example_test.go000066400000000000000000000123141264464372400243460ustar00rootroot00000000000000// Copyright 2014 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 ipv6_test import ( "fmt" "log" "net" "os" "time" "golang.org/x/net/icmp" "golang.org/x/net/ipv6" ) func ExampleConn_markingTCP() { ln, err := net.Listen("tcp", "[::]:1024") if err != nil { log.Fatal(err) } defer ln.Close() for { c, err := ln.Accept() if err != nil { log.Fatal(err) } go func(c net.Conn) { defer c.Close() if c.RemoteAddr().(*net.TCPAddr).IP.To16() != nil && c.RemoteAddr().(*net.TCPAddr).IP.To4() == nil { p := ipv6.NewConn(c) if err := p.SetTrafficClass(0x28); err != nil { // DSCP AF11 log.Fatal(err) } if err := p.SetHopLimit(128); err != nil { log.Fatal(err) } } if _, err := c.Write([]byte("HELLO-R-U-THERE-ACK")); err != nil { log.Fatal(err) } }(c) } } func ExamplePacketConn_servingOneShotMulticastDNS() { c, err := net.ListenPacket("udp6", "[::]:5353") // mDNS over UDP if err != nil { log.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) en0, err := net.InterfaceByName("en0") if err != nil { log.Fatal(err) } mDNSLinkLocal := net.UDPAddr{IP: net.ParseIP("ff02::fb")} if err := p.JoinGroup(en0, &mDNSLinkLocal); err != nil { log.Fatal(err) } defer p.LeaveGroup(en0, &mDNSLinkLocal) if err := p.SetControlMessage(ipv6.FlagDst|ipv6.FlagInterface, true); err != nil { log.Fatal(err) } var wcm ipv6.ControlMessage b := make([]byte, 1500) for { _, rcm, peer, err := p.ReadFrom(b) if err != nil { log.Fatal(err) } if !rcm.Dst.IsMulticast() || !rcm.Dst.Equal(mDNSLinkLocal.IP) { continue } wcm.IfIndex = rcm.IfIndex answers := []byte("FAKE-MDNS-ANSWERS") // fake mDNS answers, you need to implement this if _, err := p.WriteTo(answers, &wcm, peer); err != nil { log.Fatal(err) } } } func ExamplePacketConn_tracingIPPacketRoute() { // Tracing an IP packet route to www.google.com. const host = "www.google.com" ips, err := net.LookupIP(host) if err != nil { log.Fatal(err) } var dst net.IPAddr for _, ip := range ips { if ip.To16() != nil && ip.To4() == nil { dst.IP = ip fmt.Printf("using %v for tracing an IP packet route to %s\n", dst.IP, host) break } } if dst.IP == nil { log.Fatal("no AAAA record found") } c, err := net.ListenPacket("ip6:58", "::") // ICMP for IPv6 if err != nil { log.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) if err := p.SetControlMessage(ipv6.FlagHopLimit|ipv6.FlagSrc|ipv6.FlagDst|ipv6.FlagInterface, true); err != nil { log.Fatal(err) } wm := icmp.Message{ Type: ipv6.ICMPTypeEchoRequest, Code: 0, Body: &icmp.Echo{ ID: os.Getpid() & 0xffff, Data: []byte("HELLO-R-U-THERE"), }, } var f ipv6.ICMPFilter f.SetAll(true) f.Accept(ipv6.ICMPTypeTimeExceeded) f.Accept(ipv6.ICMPTypeEchoReply) if err := p.SetICMPFilter(&f); err != nil { log.Fatal(err) } var wcm ipv6.ControlMessage rb := make([]byte, 1500) for i := 1; i <= 64; i++ { // up to 64 hops wm.Body.(*icmp.Echo).Seq = i wb, err := wm.Marshal(nil) if err != nil { log.Fatal(err) } // In the real world usually there are several // multiple traffic-engineered paths for each hop. // You may need to probe a few times to each hop. begin := time.Now() wcm.HopLimit = i if _, err := p.WriteTo(wb, &wcm, &dst); err != nil { log.Fatal(err) } if err := p.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil { log.Fatal(err) } n, rcm, peer, err := p.ReadFrom(rb) if err != nil { if err, ok := err.(net.Error); ok && err.Timeout() { fmt.Printf("%v\t*\n", i) continue } log.Fatal(err) } rm, err := icmp.ParseMessage(58, rb[:n]) if err != nil { log.Fatal(err) } rtt := time.Since(begin) // In the real world you need to determine whether the // received message is yours using ControlMessage.Src, // ControlMesage.Dst, icmp.Echo.ID and icmp.Echo.Seq. switch rm.Type { case ipv6.ICMPTypeTimeExceeded: names, _ := net.LookupAddr(peer.String()) fmt.Printf("%d\t%v %+v %v\n\t%+v\n", i, peer, names, rtt, rcm) case ipv6.ICMPTypeEchoReply: names, _ := net.LookupAddr(peer.String()) fmt.Printf("%d\t%v %+v %v\n\t%+v\n", i, peer, names, rtt, rcm) return } } } func ExamplePacketConn_advertisingOSPFHello() { c, err := net.ListenPacket("ip6:89", "::") // OSPF for IPv6 if err != nil { log.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) en0, err := net.InterfaceByName("en0") if err != nil { log.Fatal(err) } allSPFRouters := net.IPAddr{IP: net.ParseIP("ff02::5")} if err := p.JoinGroup(en0, &allSPFRouters); err != nil { log.Fatal(err) } defer p.LeaveGroup(en0, &allSPFRouters) hello := make([]byte, 24) // fake hello data, you need to implement this ospf := make([]byte, 16) // fake ospf header, you need to implement this ospf[0] = 3 // version 3 ospf[1] = 1 // hello packet ospf = append(ospf, hello...) if err := p.SetChecksum(true, 12); err != nil { log.Fatal(err) } cm := ipv6.ControlMessage{ TrafficClass: 0xc0, // DSCP CS6 HopLimit: 1, IfIndex: en0.Index, } if _, err := p.WriteTo(ospf, &cm, &allSPFRouters); err != nil { log.Fatal(err) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/gen.go000066400000000000000000000117041264464372400224270ustar00rootroot00000000000000// Copyright 2013 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. // +build ignore //go:generate go run gen.go // This program generates system adaptation constants and types, // internet protocol constants and tables by reading template files // and IANA protocol registries. package main import ( "bytes" "encoding/xml" "fmt" "go/format" "io" "io/ioutil" "net/http" "os" "os/exec" "runtime" "strconv" "strings" ) func main() { if err := genzsys(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } if err := geniana(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func genzsys() error { defs := "defs_" + runtime.GOOS + ".go" f, err := os.Open(defs) if err != nil { if os.IsNotExist(err) { return nil } return err } f.Close() cmd := exec.Command("go", "tool", "cgo", "-godefs", defs) b, err := cmd.Output() if err != nil { return err } // The ipv6 pacakge still supports go1.2, and so we need to // take care of additional platforms in go1.3 and above for // working with go1.2. switch { case runtime.GOOS == "dragonfly" || runtime.GOOS == "solaris": b = bytes.Replace(b, []byte("package ipv6\n"), []byte("// +build "+runtime.GOOS+"\n\npackage ipv6\n"), 1) case runtime.GOOS == "linux" && (runtime.GOARCH == "arm64" || runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le"): b = bytes.Replace(b, []byte("package ipv6\n"), []byte("// +build "+runtime.GOOS+","+runtime.GOARCH+"\n\npackage ipv6\n"), 1) } b, err = format.Source(b) if err != nil { return err } zsys := "zsys_" + runtime.GOOS + ".go" switch runtime.GOOS { case "freebsd", "linux": zsys = "zsys_" + runtime.GOOS + "_" + runtime.GOARCH + ".go" } if err := ioutil.WriteFile(zsys, b, 0644); err != nil { return err } return nil } var registries = []struct { url string parse func(io.Writer, io.Reader) error }{ { "http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml", parseICMPv6Parameters, }, } func geniana() error { var bb bytes.Buffer fmt.Fprintf(&bb, "// go generate gen.go\n") fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n") fmt.Fprintf(&bb, "package ipv6\n\n") for _, r := range registries { resp, err := http.Get(r.url) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("got HTTP status code %v for %v\n", resp.StatusCode, r.url) } if err := r.parse(&bb, resp.Body); err != nil { return err } fmt.Fprintf(&bb, "\n") } b, err := format.Source(bb.Bytes()) if err != nil { return err } if err := ioutil.WriteFile("iana.go", b, 0644); err != nil { return err } return nil } func parseICMPv6Parameters(w io.Writer, r io.Reader) error { dec := xml.NewDecoder(r) var icp icmpv6Parameters if err := dec.Decode(&icp); err != nil { return err } prs := icp.escape() fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated) fmt.Fprintf(w, "const (\n") for _, pr := range prs { if pr.Name == "" { continue } fmt.Fprintf(w, "ICMPType%s ICMPType = %d", pr.Name, pr.Value) fmt.Fprintf(w, "// %s\n", pr.OrigName) } fmt.Fprintf(w, ")\n\n") fmt.Fprintf(w, "// %s, Updated: %s\n", icp.Title, icp.Updated) fmt.Fprintf(w, "var icmpTypes = map[ICMPType]string{\n") for _, pr := range prs { if pr.Name == "" { continue } fmt.Fprintf(w, "%d: %q,\n", pr.Value, strings.ToLower(pr.OrigName)) } fmt.Fprintf(w, "}\n") return nil } type icmpv6Parameters struct { XMLName xml.Name `xml:"registry"` Title string `xml:"title"` Updated string `xml:"updated"` Registries []struct { Title string `xml:"title"` Records []struct { Value string `xml:"value"` Name string `xml:"name"` } `xml:"record"` } `xml:"registry"` } type canonICMPv6ParamRecord struct { OrigName string Name string Value int } func (icp *icmpv6Parameters) escape() []canonICMPv6ParamRecord { id := -1 for i, r := range icp.Registries { if strings.Contains(r.Title, "Type") || strings.Contains(r.Title, "type") { id = i break } } if id < 0 { return nil } prs := make([]canonICMPv6ParamRecord, len(icp.Registries[id].Records)) sr := strings.NewReplacer( "Messages", "", "Message", "", "ICMP", "", "+", "P", "-", "", "/", "", ".", "", " ", "", ) for i, pr := range icp.Registries[id].Records { if strings.Contains(pr.Name, "Reserved") || strings.Contains(pr.Name, "Unassigned") || strings.Contains(pr.Name, "Deprecated") || strings.Contains(pr.Name, "Experiment") || strings.Contains(pr.Name, "experiment") { continue } ss := strings.Split(pr.Name, "\n") if len(ss) > 1 { prs[i].Name = strings.Join(ss, " ") } else { prs[i].Name = ss[0] } s := strings.TrimSpace(prs[i].Name) prs[i].OrigName = s prs[i].Name = sr.Replace(s) prs[i].Value, _ = strconv.Atoi(pr.Value) } return prs } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/genericopt_posix.go000066400000000000000000000025441264464372400252410ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin dragonfly freebsd linux netbsd openbsd windows package ipv6 import "syscall" // TrafficClass returns the traffic class field value for outgoing // packets. func (c *genericOpt) TrafficClass() (int, error) { if !c.ok() { return 0, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return 0, err } return getInt(fd, &sockOpts[ssoTrafficClass]) } // SetTrafficClass sets the traffic class field value for future // outgoing packets. func (c *genericOpt) SetTrafficClass(tclass int) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setInt(fd, &sockOpts[ssoTrafficClass], tclass) } // HopLimit returns the hop limit field value for outgoing packets. func (c *genericOpt) HopLimit() (int, error) { if !c.ok() { return 0, syscall.EINVAL } fd, err := c.sysfd() if err != nil { return 0, err } return getInt(fd, &sockOpts[ssoHopLimit]) } // SetHopLimit sets the hop limit field value for future outgoing // packets. func (c *genericOpt) SetHopLimit(hoplim int) error { if !c.ok() { return syscall.EINVAL } fd, err := c.sysfd() if err != nil { return err } return setInt(fd, &sockOpts[ssoHopLimit], hoplim) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/genericopt_stub.go000066400000000000000000000015011264464372400250440ustar00rootroot00000000000000// Copyright 2013 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. // +build nacl plan9 solaris package ipv6 // TrafficClass returns the traffic class field value for outgoing // packets. func (c *genericOpt) TrafficClass() (int, error) { return 0, errOpNoSupport } // SetTrafficClass sets the traffic class field value for future // outgoing packets. func (c *genericOpt) SetTrafficClass(tclass int) error { return errOpNoSupport } // HopLimit returns the hop limit field value for outgoing packets. func (c *genericOpt) HopLimit() (int, error) { return 0, errOpNoSupport } // SetHopLimit sets the hop limit field value for future outgoing // packets. func (c *genericOpt) SetHopLimit(hoplim int) error { return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/header.go000066400000000000000000000026731264464372400231130ustar00rootroot00000000000000// Copyright 2014 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 ipv6 import ( "fmt" "net" ) const ( Version = 6 // protocol version HeaderLen = 40 // header length ) // A Header represents an IPv6 base header. type Header struct { Version int // protocol version TrafficClass int // traffic class FlowLabel int // flow label PayloadLen int // payload length NextHeader int // next header HopLimit int // hop limit Src net.IP // source address Dst net.IP // destination address } func (h *Header) String() string { if h == nil { return "" } return fmt.Sprintf("ver=%d tclass=%#x flowlbl=%#x payloadlen=%d nxthdr=%d hoplim=%d src=%v dst=%v", h.Version, h.TrafficClass, h.FlowLabel, h.PayloadLen, h.NextHeader, h.HopLimit, h.Src, h.Dst) } // ParseHeader parses b as an IPv6 base header. func ParseHeader(b []byte) (*Header, error) { if len(b) < HeaderLen { return nil, errHeaderTooShort } h := &Header{ Version: int(b[0]) >> 4, TrafficClass: int(b[0]&0x0f)<<4 | int(b[1])>>4, FlowLabel: int(b[1]&0x0f)<<16 | int(b[2])<<8 | int(b[3]), PayloadLen: int(b[4])<<8 | int(b[5]), NextHeader: int(b[6]), HopLimit: int(b[7]), } h.Src = make(net.IP, net.IPv6len) copy(h.Src, b[8:24]) h.Dst = make(net.IP, net.IPv6len) copy(h.Dst, b[24:40]) return h, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/header_test.go000066400000000000000000000023131264464372400241410ustar00rootroot00000000000000// Copyright 2014 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 ipv6_test import ( "net" "reflect" "strings" "testing" "golang.org/x/net/internal/iana" "golang.org/x/net/ipv6" ) var ( wireHeaderFromKernel = [ipv6.HeaderLen]byte{ 0x69, 0x8b, 0xee, 0xf1, 0xca, 0xfe, 0x2c, 0x01, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, } testHeader = &ipv6.Header{ Version: ipv6.Version, TrafficClass: iana.DiffServAF43, FlowLabel: 0xbeef1, PayloadLen: 0xcafe, NextHeader: iana.ProtocolIPv6Frag, HopLimit: 1, Src: net.ParseIP("2001:db8:1::1"), Dst: net.ParseIP("2001:db8:2::1"), } ) func TestParseHeader(t *testing.T) { h, err := ipv6.ParseHeader(wireHeaderFromKernel[:]) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(h, testHeader) { t.Fatalf("got %#v; want %#v", h, testHeader) } s := h.String() if strings.Contains(s, ",") { t.Fatalf("should be space-separated values: %s", s) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/helper.go000066400000000000000000000014541264464372400231360ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import ( "errors" "net" ) var ( errMissingAddress = errors.New("missing address") errHeaderTooShort = errors.New("header too short") errInvalidConnType = errors.New("invalid conn type") errOpNoSupport = errors.New("operation not supported") errNoSuchInterface = errors.New("no such interface") ) func boolint(b bool) int { if b { return 1 } return 0 } func netAddrToIP16(a net.Addr) net.IP { switch v := a.(type) { case *net.UDPAddr: if ip := v.IP.To16(); ip != nil && ip.To4() == nil { return ip } case *net.IPAddr: if ip := v.IP.To16(); ip != nil && ip.To4() == nil { return ip } } return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/helper_stub.go000066400000000000000000000006511264464372400241710ustar00rootroot00000000000000// Copyright 2013 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. // +build nacl plan9 solaris package ipv6 func (c *genericOpt) sysfd() (int, error) { return 0, errOpNoSupport } func (c *dgramOpt) sysfd() (int, error) { return 0, errOpNoSupport } func (c *payloadHandler) sysfd() (int, error) { return 0, errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/helper_unix.go000066400000000000000000000020151264464372400241730ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin dragonfly freebsd linux netbsd openbsd package ipv6 import ( "net" "reflect" ) func (c *genericOpt) sysfd() (int, error) { switch p := c.Conn.(type) { case *net.TCPConn, *net.UDPConn, *net.IPConn: return sysfd(p) } return 0, errInvalidConnType } func (c *dgramOpt) sysfd() (int, error) { switch p := c.PacketConn.(type) { case *net.UDPConn, *net.IPConn: return sysfd(p.(net.Conn)) } return 0, errInvalidConnType } func (c *payloadHandler) sysfd() (int, error) { return sysfd(c.PacketConn.(net.Conn)) } func sysfd(c net.Conn) (int, error) { cv := reflect.ValueOf(c) switch ce := cv.Elem(); ce.Kind() { case reflect.Struct: nfd := ce.FieldByName("conn").FieldByName("fd") switch fe := nfd.Elem(); fe.Kind() { case reflect.Struct: fd := fe.FieldByName("sysfd") return int(fd.Int()), nil } } return 0, errInvalidConnType } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/helper_windows.go000066400000000000000000000021271264464372400247060ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import ( "net" "reflect" "syscall" ) func (c *genericOpt) sysfd() (syscall.Handle, error) { switch p := c.Conn.(type) { case *net.TCPConn, *net.UDPConn, *net.IPConn: return sysfd(p) } return syscall.InvalidHandle, errInvalidConnType } func (c *dgramOpt) sysfd() (syscall.Handle, error) { switch p := c.PacketConn.(type) { case *net.UDPConn, *net.IPConn: return sysfd(p.(net.Conn)) } return syscall.InvalidHandle, errInvalidConnType } func (c *payloadHandler) sysfd() (syscall.Handle, error) { return sysfd(c.PacketConn.(net.Conn)) } func sysfd(c net.Conn) (syscall.Handle, error) { cv := reflect.ValueOf(c) switch ce := cv.Elem(); ce.Kind() { case reflect.Struct: netfd := ce.FieldByName("conn").FieldByName("fd") switch fe := netfd.Elem(); fe.Kind() { case reflect.Struct: fd := fe.FieldByName("sysfd") return syscall.Handle(fd.Uint()), nil } } return syscall.InvalidHandle, errInvalidConnType } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/iana.go000066400000000000000000000112561264464372400225700ustar00rootroot00000000000000// go generate gen.go // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT package ipv6 // Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2015-07-07 const ( ICMPTypeDestinationUnreachable ICMPType = 1 // Destination Unreachable ICMPTypePacketTooBig ICMPType = 2 // Packet Too Big ICMPTypeTimeExceeded ICMPType = 3 // Time Exceeded ICMPTypeParameterProblem ICMPType = 4 // Parameter Problem ICMPTypeEchoRequest ICMPType = 128 // Echo Request ICMPTypeEchoReply ICMPType = 129 // Echo Reply ICMPTypeMulticastListenerQuery ICMPType = 130 // Multicast Listener Query ICMPTypeMulticastListenerReport ICMPType = 131 // Multicast Listener Report ICMPTypeMulticastListenerDone ICMPType = 132 // Multicast Listener Done ICMPTypeRouterSolicitation ICMPType = 133 // Router Solicitation ICMPTypeRouterAdvertisement ICMPType = 134 // Router Advertisement ICMPTypeNeighborSolicitation ICMPType = 135 // Neighbor Solicitation ICMPTypeNeighborAdvertisement ICMPType = 136 // Neighbor Advertisement ICMPTypeRedirect ICMPType = 137 // Redirect Message ICMPTypeRouterRenumbering ICMPType = 138 // Router Renumbering ICMPTypeNodeInformationQuery ICMPType = 139 // ICMP Node Information Query ICMPTypeNodeInformationResponse ICMPType = 140 // ICMP Node Information Response ICMPTypeInverseNeighborDiscoverySolicitation ICMPType = 141 // Inverse Neighbor Discovery Solicitation Message ICMPTypeInverseNeighborDiscoveryAdvertisement ICMPType = 142 // Inverse Neighbor Discovery Advertisement Message ICMPTypeVersion2MulticastListenerReport ICMPType = 143 // Version 2 Multicast Listener Report ICMPTypeHomeAgentAddressDiscoveryRequest ICMPType = 144 // Home Agent Address Discovery Request Message ICMPTypeHomeAgentAddressDiscoveryReply ICMPType = 145 // Home Agent Address Discovery Reply Message ICMPTypeMobilePrefixSolicitation ICMPType = 146 // Mobile Prefix Solicitation ICMPTypeMobilePrefixAdvertisement ICMPType = 147 // Mobile Prefix Advertisement ICMPTypeCertificationPathSolicitation ICMPType = 148 // Certification Path Solicitation Message ICMPTypeCertificationPathAdvertisement ICMPType = 149 // Certification Path Advertisement Message ICMPTypeMulticastRouterAdvertisement ICMPType = 151 // Multicast Router Advertisement ICMPTypeMulticastRouterSolicitation ICMPType = 152 // Multicast Router Solicitation ICMPTypeMulticastRouterTermination ICMPType = 153 // Multicast Router Termination ICMPTypeFMIPv6 ICMPType = 154 // FMIPv6 Messages ICMPTypeRPLControl ICMPType = 155 // RPL Control Message ICMPTypeILNPv6LocatorUpdate ICMPType = 156 // ILNPv6 Locator Update Message ICMPTypeDuplicateAddressRequest ICMPType = 157 // Duplicate Address Request ICMPTypeDuplicateAddressConfirmation ICMPType = 158 // Duplicate Address Confirmation ICMPTypeMPLControl ICMPType = 159 // MPL Control Message ) // Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2015-07-07 var icmpTypes = map[ICMPType]string{ 1: "destination unreachable", 2: "packet too big", 3: "time exceeded", 4: "parameter problem", 128: "echo request", 129: "echo reply", 130: "multicast listener query", 131: "multicast listener report", 132: "multicast listener done", 133: "router solicitation", 134: "router advertisement", 135: "neighbor solicitation", 136: "neighbor advertisement", 137: "redirect message", 138: "router renumbering", 139: "icmp node information query", 140: "icmp node information response", 141: "inverse neighbor discovery solicitation message", 142: "inverse neighbor discovery advertisement message", 143: "version 2 multicast listener report", 144: "home agent address discovery request message", 145: "home agent address discovery reply message", 146: "mobile prefix solicitation", 147: "mobile prefix advertisement", 148: "certification path solicitation message", 149: "certification path advertisement message", 151: "multicast router advertisement", 152: "multicast router solicitation", 153: "multicast router termination", 154: "fmipv6 messages", 155: "rpl control message", 156: "ilnpv6 locator update message", 157: "duplicate address request", 158: "duplicate address confirmation", 159: "mpl control message", } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/icmp.go000066400000000000000000000027611264464372400226110ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import "golang.org/x/net/internal/iana" // An ICMPType represents a type of ICMP message. type ICMPType int func (typ ICMPType) String() string { s, ok := icmpTypes[typ] if !ok { return "" } return s } // Protocol returns the ICMPv6 protocol number. func (typ ICMPType) Protocol() int { return iana.ProtocolIPv6ICMP } // An ICMPFilter represents an ICMP message filter for incoming // packets. The filter belongs to a packet delivery path on a host and // it cannot interact with forwarding packets or tunnel-outer packets. // // Note: RFC 2460 defines a reasonable role model. A node means a // device that implements IP. A router means a node that forwards IP // packets not explicitly addressed to itself, and a host means a node // that is not a router. type ICMPFilter struct { sysICMPv6Filter } // Accept accepts incoming ICMP packets including the type field value // typ. func (f *ICMPFilter) Accept(typ ICMPType) { f.accept(typ) } // Block blocks incoming ICMP packets including the type field value // typ. func (f *ICMPFilter) Block(typ ICMPType) { f.block(typ) } // SetAll sets the filter action to the filter. func (f *ICMPFilter) SetAll(block bool) { f.setAll(block) } // WillBlock reports whether the ICMP type will be blocked. func (f *ICMPFilter) WillBlock(typ ICMPType) bool { return f.willBlock(typ) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/icmp_bsd.go000066400000000000000000000012411264464372400234310ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin dragonfly freebsd netbsd openbsd package ipv6 func (f *sysICMPv6Filter) accept(typ ICMPType) { f.Filt[typ>>5] |= 1 << (uint32(typ) & 31) } func (f *sysICMPv6Filter) block(typ ICMPType) { f.Filt[typ>>5] &^= 1 << (uint32(typ) & 31) } func (f *sysICMPv6Filter) setAll(block bool) { for i := range f.Filt { if block { f.Filt[i] = 0 } else { f.Filt[i] = 1<<32 - 1 } } } func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool { return f.Filt[typ>>5]&(1<<(uint32(typ)&31)) == 0 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/icmp_linux.go000066400000000000000000000011561264464372400240250ustar00rootroot00000000000000// Copyright 2013 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 ipv6 func (f *sysICMPv6Filter) accept(typ ICMPType) { f.Data[typ>>5] &^= 1 << (uint32(typ) & 31) } func (f *sysICMPv6Filter) block(typ ICMPType) { f.Data[typ>>5] |= 1 << (uint32(typ) & 31) } func (f *sysICMPv6Filter) setAll(block bool) { for i := range f.Data { if block { f.Data[i] = 1<<32 - 1 } else { f.Data[i] = 0 } } } func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool { return f.Data[typ>>5]&(1<<(uint32(typ)&31)) != 0 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/icmp_solaris.go000066400000000000000000000010441264464372400243360ustar00rootroot00000000000000// Copyright 2013 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. // +build solaris package ipv6 func (f *sysICMPv6Filter) accept(typ ICMPType) { // TODO(mikio): implement this } func (f *sysICMPv6Filter) block(typ ICMPType) { // TODO(mikio): implement this } func (f *sysICMPv6Filter) setAll(block bool) { // TODO(mikio): implement this } func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool { // TODO(mikio): implement this return false } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/icmp_stub.go000066400000000000000000000007101264464372400236360ustar00rootroot00000000000000// Copyright 2013 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. // +build nacl plan9 package ipv6 type sysICMPv6Filter struct { } func (f *sysICMPv6Filter) accept(typ ICMPType) { } func (f *sysICMPv6Filter) block(typ ICMPType) { } func (f *sysICMPv6Filter) setAll(block bool) { } func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool { return false } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/icmp_test.go000066400000000000000000000037221264464372400236460ustar00rootroot00000000000000// Copyright 2013 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 ipv6_test import ( "net" "reflect" "runtime" "testing" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv6" ) var icmpStringTests = []struct { in ipv6.ICMPType out string }{ {ipv6.ICMPTypeDestinationUnreachable, "destination unreachable"}, {256, ""}, } func TestICMPString(t *testing.T) { for _, tt := range icmpStringTests { s := tt.in.String() if s != tt.out { t.Errorf("got %s; want %s", s, tt.out) } } } func TestICMPFilter(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } var f ipv6.ICMPFilter for _, toggle := range []bool{false, true} { f.SetAll(toggle) for _, typ := range []ipv6.ICMPType{ ipv6.ICMPTypeDestinationUnreachable, ipv6.ICMPTypeEchoReply, ipv6.ICMPTypeNeighborSolicitation, ipv6.ICMPTypeDuplicateAddressConfirmation, } { f.Accept(typ) if f.WillBlock(typ) { t.Errorf("ipv6.ICMPFilter.Set(%v, false) failed", typ) } f.Block(typ) if !f.WillBlock(typ) { t.Errorf("ipv6.ICMPFilter.Set(%v, true) failed", typ) } } } } func TestSetICMPFilter(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } c, err := net.ListenPacket("ip6:ipv6-icmp", "::1") if err != nil { t.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) var f ipv6.ICMPFilter f.SetAll(true) f.Accept(ipv6.ICMPTypeEchoRequest) f.Accept(ipv6.ICMPTypeEchoReply) if err := p.SetICMPFilter(&f); err != nil { t.Fatal(err) } kf, err := p.ICMPFilter() if err != nil { t.Fatal(err) } if !reflect.DeepEqual(kf, &f) { t.Fatalf("got %#v; want %#v", kf, f) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/icmp_windows.go000066400000000000000000000011221264464372400243510ustar00rootroot00000000000000// Copyright 2013 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 ipv6 type sysICMPv6Filter struct { // TODO(mikio): implement this } func (f *sysICMPv6Filter) accept(typ ICMPType) { // TODO(mikio): implement this } func (f *sysICMPv6Filter) block(typ ICMPType) { // TODO(mikio): implement this } func (f *sysICMPv6Filter) setAll(block bool) { // TODO(mikio): implement this } func (f *sysICMPv6Filter) willBlock(typ ICMPType) bool { // TODO(mikio): implement this return false } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/mocktransponder_test.go000066400000000000000000000011131264464372400261170ustar00rootroot00000000000000// Copyright 2013 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 ipv6_test import ( "net" "testing" ) func connector(t *testing.T, network, addr string, done chan<- bool) { defer func() { done <- true }() c, err := net.Dial(network, addr) if err != nil { t.Error(err) return } c.Close() } func acceptor(t *testing.T, ln net.Listener, done chan<- bool) { defer func() { done <- true }() c, err := ln.Accept() if err != nil { t.Error(err) return } c.Close() } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/multicast_test.go000066400000000000000000000161361264464372400247260ustar00rootroot00000000000000// Copyright 2013 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 ipv6_test import ( "bytes" "net" "os" "runtime" "testing" "time" "golang.org/x/net/icmp" "golang.org/x/net/internal/iana" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv6" ) var packetConnReadWriteMulticastUDPTests = []struct { addr string grp, src *net.UDPAddr }{ {"[ff02::]:0", &net.UDPAddr{IP: net.ParseIP("ff02::114")}, nil}, // see RFC 4727 {"[ff30::8000:0]:0", &net.UDPAddr{IP: net.ParseIP("ff30::8000:1")}, &net.UDPAddr{IP: net.IPv6loopback}}, // see RFC 5771 } func TestPacketConnReadWriteMulticastUDP(t *testing.T) { switch runtime.GOOS { case "freebsd": // due to a bug on loopback marking // See http://www.freebsd.org/cgi/query-pr.cgi?pr=180065. t.Skipf("not supported on %s", runtime.GOOS) case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagMulticast|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } for _, tt := range packetConnReadWriteMulticastUDPTests { c, err := net.ListenPacket("udp6", tt.addr) if err != nil { t.Fatal(err) } defer c.Close() grp := *tt.grp grp.Port = c.LocalAddr().(*net.UDPAddr).Port p := ipv6.NewPacketConn(c) defer p.Close() if tt.src == nil { if err := p.JoinGroup(ifi, &grp); err != nil { t.Fatal(err) } defer p.LeaveGroup(ifi, &grp) } else { if err := p.JoinSourceSpecificGroup(ifi, &grp, tt.src); err != nil { switch runtime.GOOS { case "freebsd", "linux": default: // platforms that don't support MLDv2 fail here t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } defer p.LeaveSourceSpecificGroup(ifi, &grp, tt.src) } if err := p.SetMulticastInterface(ifi); err != nil { t.Fatal(err) } if _, err := p.MulticastInterface(); err != nil { t.Fatal(err) } if err := p.SetMulticastLoopback(true); err != nil { t.Fatal(err) } if _, err := p.MulticastLoopback(); err != nil { t.Fatal(err) } cm := ipv6.ControlMessage{ TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, Src: net.IPv6loopback, IfIndex: ifi.Index, } cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU wb := []byte("HELLO-R-U-THERE") for i, toggle := range []bool{true, false, true} { if err := p.SetControlMessage(cf, toggle); err != nil { if nettest.ProtocolNotSupported(err) { t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil { t.Fatal(err) } cm.HopLimit = i + 1 if n, err := p.WriteTo(wb, &cm, &grp); err != nil { t.Fatal(err) } else if n != len(wb) { t.Fatal(err) } rb := make([]byte, 128) if n, _, _, err := p.ReadFrom(rb); err != nil { t.Fatal(err) } else if !bytes.Equal(rb[:n], wb) { t.Fatalf("got %v; want %v", rb[:n], wb) } } } } var packetConnReadWriteMulticastICMPTests = []struct { grp, src *net.IPAddr }{ {&net.IPAddr{IP: net.ParseIP("ff02::114")}, nil}, // see RFC 4727 {&net.IPAddr{IP: net.ParseIP("ff30::8000:1")}, &net.IPAddr{IP: net.IPv6loopback}}, // see RFC 5771 } func TestPacketConnReadWriteMulticastICMP(t *testing.T) { switch runtime.GOOS { case "freebsd": // due to a bug on loopback marking // See http://www.freebsd.org/cgi/query-pr.cgi?pr=180065. t.Skipf("not supported on %s", runtime.GOOS) case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagMulticast|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } for _, tt := range packetConnReadWriteMulticastICMPTests { c, err := net.ListenPacket("ip6:ipv6-icmp", "::") if err != nil { t.Fatal(err) } defer c.Close() pshicmp := icmp.IPv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, tt.grp.IP) p := ipv6.NewPacketConn(c) defer p.Close() if tt.src == nil { if err := p.JoinGroup(ifi, tt.grp); err != nil { t.Fatal(err) } defer p.LeaveGroup(ifi, tt.grp) } else { if err := p.JoinSourceSpecificGroup(ifi, tt.grp, tt.src); err != nil { switch runtime.GOOS { case "freebsd", "linux": default: // platforms that don't support MLDv2 fail here t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } defer p.LeaveSourceSpecificGroup(ifi, tt.grp, tt.src) } if err := p.SetMulticastInterface(ifi); err != nil { t.Fatal(err) } if _, err := p.MulticastInterface(); err != nil { t.Fatal(err) } if err := p.SetMulticastLoopback(true); err != nil { t.Fatal(err) } if _, err := p.MulticastLoopback(); err != nil { t.Fatal(err) } cm := ipv6.ControlMessage{ TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, Src: net.IPv6loopback, IfIndex: ifi.Index, } cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU var f ipv6.ICMPFilter f.SetAll(true) f.Accept(ipv6.ICMPTypeEchoReply) if err := p.SetICMPFilter(&f); err != nil { t.Fatal(err) } var psh []byte for i, toggle := range []bool{true, false, true} { if toggle { psh = nil if err := p.SetChecksum(true, 2); err != nil { t.Fatal(err) } } else { psh = pshicmp // Some platforms never allow to // disable the kernel checksum // processing. p.SetChecksum(false, -1) } wb, err := (&icmp.Message{ Type: ipv6.ICMPTypeEchoRequest, Code: 0, Body: &icmp.Echo{ ID: os.Getpid() & 0xffff, Seq: i + 1, Data: []byte("HELLO-R-U-THERE"), }, }).Marshal(psh) if err != nil { t.Fatal(err) } if err := p.SetControlMessage(cf, toggle); err != nil { if nettest.ProtocolNotSupported(err) { t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } if err := p.SetDeadline(time.Now().Add(200 * time.Millisecond)); err != nil { t.Fatal(err) } cm.HopLimit = i + 1 if n, err := p.WriteTo(wb, &cm, tt.grp); err != nil { t.Fatal(err) } else if n != len(wb) { t.Fatalf("got %v; want %v", n, len(wb)) } rb := make([]byte, 128) if n, _, _, err := p.ReadFrom(rb); err != nil { switch runtime.GOOS { case "darwin": // older darwin kernels have some limitation on receiving icmp packet through raw socket t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } else { if m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, rb[:n]); err != nil { t.Fatal(err) } else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 { t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0) } } } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/multicastlistener_test.go000066400000000000000000000132061264464372400264670ustar00rootroot00000000000000// Copyright 2013 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 ipv6_test import ( "fmt" "net" "runtime" "testing" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv6" ) var udpMultipleGroupListenerTests = []net.Addr{ &net.UDPAddr{IP: net.ParseIP("ff02::114")}, // see RFC 4727 &net.UDPAddr{IP: net.ParseIP("ff02::1:114")}, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}, } func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } for _, gaddr := range udpMultipleGroupListenerTests { c, err := net.ListenPacket("udp6", "[::]:0") // wildcard address with non-reusable port if err != nil { t.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) var mift []*net.Interface ift, err := net.Interfaces() if err != nil { t.Fatal(err) } for i, ifi := range ift { if _, ok := nettest.IsMulticastCapable("ip6", &ifi); !ok { continue } if err := p.JoinGroup(&ifi, gaddr); err != nil { t.Fatal(err) } mift = append(mift, &ift[i]) } for _, ifi := range mift { if err := p.LeaveGroup(ifi, gaddr); err != nil { t.Fatal(err) } } } } func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } for _, gaddr := range udpMultipleGroupListenerTests { c1, err := net.ListenPacket("udp6", "[ff02::]:1024") // wildcard address with reusable port if err != nil { t.Fatal(err) } defer c1.Close() c2, err := net.ListenPacket("udp6", "[ff02::]:1024") // wildcard address with reusable port if err != nil { t.Fatal(err) } defer c2.Close() var ps [2]*ipv6.PacketConn ps[0] = ipv6.NewPacketConn(c1) ps[1] = ipv6.NewPacketConn(c2) var mift []*net.Interface ift, err := net.Interfaces() if err != nil { t.Fatal(err) } for i, ifi := range ift { if _, ok := nettest.IsMulticastCapable("ip6", &ifi); !ok { continue } for _, p := range ps { if err := p.JoinGroup(&ifi, gaddr); err != nil { t.Fatal(err) } } mift = append(mift, &ift[i]) } for _, ifi := range mift { for _, p := range ps { if err := p.LeaveGroup(ifi, gaddr); err != nil { t.Fatal(err) } } } } } func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727 type ml struct { c *ipv6.PacketConn ifi *net.Interface } var mlt []*ml ift, err := net.Interfaces() if err != nil { t.Fatal(err) } for i, ifi := range ift { ip, ok := nettest.IsMulticastCapable("ip6", &ifi) if !ok { continue } c, err := net.ListenPacket("udp6", fmt.Sprintf("[%s%%%s]:1024", ip.String(), ifi.Name)) // unicast address with non-reusable port if err != nil { t.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) if err := p.JoinGroup(&ifi, &gaddr); err != nil { t.Fatal(err) } mlt = append(mlt, &ml{p, &ift[i]}) } for _, m := range mlt { if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil { t.Fatal(err) } } } func TestIPSinglePacketConnWithSingleGroupListener(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } c, err := net.ListenPacket("ip6:ipv6-icmp", "::") // wildcard address if err != nil { t.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727 var mift []*net.Interface ift, err := net.Interfaces() if err != nil { t.Fatal(err) } for i, ifi := range ift { if _, ok := nettest.IsMulticastCapable("ip6", &ifi); !ok { continue } if err := p.JoinGroup(&ifi, &gaddr); err != nil { t.Fatal(err) } mift = append(mift, &ift[i]) } for _, ifi := range mift { if err := p.LeaveGroup(ifi, &gaddr); err != nil { t.Fatal(err) } } } func TestIPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) { switch runtime.GOOS { case "darwin", "dragonfly", "openbsd": // platforms that return fe80::1%lo0: bind: can't assign requested address t.Skipf("not supported on %s", runtime.GOOS) case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } gaddr := net.IPAddr{IP: net.ParseIP("ff02::114")} // see RFC 4727 type ml struct { c *ipv6.PacketConn ifi *net.Interface } var mlt []*ml ift, err := net.Interfaces() if err != nil { t.Fatal(err) } for i, ifi := range ift { ip, ok := nettest.IsMulticastCapable("ip6", &ifi) if !ok { continue } c, err := net.ListenPacket("ip6:ipv6-icmp", fmt.Sprintf("%s%%%s", ip.String(), ifi.Name)) // unicast address if err != nil { t.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) if err := p.JoinGroup(&ifi, &gaddr); err != nil { t.Fatal(err) } mlt = append(mlt, &ml{p, &ift[i]}) } for _, m := range mlt { if err := m.c.LeaveGroup(m.ifi, &gaddr); err != nil { t.Fatal(err) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/multicastsockopt_test.go000066400000000000000000000102471264464372400263260ustar00rootroot00000000000000// Copyright 2013 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 ipv6_test import ( "net" "runtime" "testing" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv6" ) var packetConnMulticastSocketOptionTests = []struct { net, proto, addr string grp, src net.Addr }{ {"udp6", "", "[ff02::]:0", &net.UDPAddr{IP: net.ParseIP("ff02::114")}, nil}, // see RFC 4727 {"ip6", ":ipv6-icmp", "::", &net.IPAddr{IP: net.ParseIP("ff02::115")}, nil}, // see RFC 4727 {"udp6", "", "[ff30::8000:0]:0", &net.UDPAddr{IP: net.ParseIP("ff30::8000:1")}, &net.UDPAddr{IP: net.IPv6loopback}}, // see RFC 5771 {"ip6", ":ipv6-icmp", "::", &net.IPAddr{IP: net.ParseIP("ff30::8000:2")}, &net.IPAddr{IP: net.IPv6loopback}}, // see RFC 5771 } func TestPacketConnMulticastSocketOptions(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagMulticast|net.FlagLoopback) if ifi == nil { t.Skipf("not available on %s", runtime.GOOS) } m, ok := nettest.SupportsRawIPSocket() for _, tt := range packetConnMulticastSocketOptionTests { if tt.net == "ip6" && !ok { t.Log(m) continue } c, err := net.ListenPacket(tt.net+tt.proto, tt.addr) if err != nil { t.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) defer p.Close() if tt.src == nil { testMulticastSocketOptions(t, p, ifi, tt.grp) } else { testSourceSpecificMulticastSocketOptions(t, p, ifi, tt.grp, tt.src) } } } type testIPv6MulticastConn interface { MulticastHopLimit() (int, error) SetMulticastHopLimit(ttl int) error MulticastLoopback() (bool, error) SetMulticastLoopback(bool) error JoinGroup(*net.Interface, net.Addr) error LeaveGroup(*net.Interface, net.Addr) error JoinSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error LeaveSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error ExcludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error IncludeSourceSpecificGroup(*net.Interface, net.Addr, net.Addr) error } func testMulticastSocketOptions(t *testing.T, c testIPv6MulticastConn, ifi *net.Interface, grp net.Addr) { const hoplim = 255 if err := c.SetMulticastHopLimit(hoplim); err != nil { t.Error(err) return } if v, err := c.MulticastHopLimit(); err != nil { t.Error(err) return } else if v != hoplim { t.Errorf("got %v; want %v", v, hoplim) return } for _, toggle := range []bool{true, false} { if err := c.SetMulticastLoopback(toggle); err != nil { t.Error(err) return } if v, err := c.MulticastLoopback(); err != nil { t.Error(err) return } else if v != toggle { t.Errorf("got %v; want %v", v, toggle) return } } if err := c.JoinGroup(ifi, grp); err != nil { t.Error(err) return } if err := c.LeaveGroup(ifi, grp); err != nil { t.Error(err) return } } func testSourceSpecificMulticastSocketOptions(t *testing.T, c testIPv6MulticastConn, ifi *net.Interface, grp, src net.Addr) { // MCAST_JOIN_GROUP -> MCAST_BLOCK_SOURCE -> MCAST_UNBLOCK_SOURCE -> MCAST_LEAVE_GROUP if err := c.JoinGroup(ifi, grp); err != nil { t.Error(err) return } if err := c.ExcludeSourceSpecificGroup(ifi, grp, src); err != nil { switch runtime.GOOS { case "freebsd", "linux": default: // platforms that don't support MLDv2 fail here t.Logf("not supported on %s", runtime.GOOS) return } t.Error(err) return } if err := c.IncludeSourceSpecificGroup(ifi, grp, src); err != nil { t.Error(err) return } if err := c.LeaveGroup(ifi, grp); err != nil { t.Error(err) return } // MCAST_JOIN_SOURCE_GROUP -> MCAST_LEAVE_SOURCE_GROUP if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil { t.Error(err) return } if err := c.LeaveSourceSpecificGroup(ifi, grp, src); err != nil { t.Error(err) return } // MCAST_JOIN_SOURCE_GROUP -> MCAST_LEAVE_GROUP if err := c.JoinSourceSpecificGroup(ifi, grp, src); err != nil { t.Error(err) return } if err := c.LeaveGroup(ifi, grp); err != nil { t.Error(err) return } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/payload.go000066400000000000000000000006051264464372400233050ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import "net" // A payloadHandler represents the IPv6 datagram payload handler. type payloadHandler struct { net.PacketConn rawOpt } func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/payload_cmsg.go000066400000000000000000000037151264464372400243230ustar00rootroot00000000000000// Copyright 2013 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. // +build !nacl,!plan9,!windows package ipv6 import ( "net" "syscall" ) // ReadFrom reads a payload of the received IPv6 datagram, from the // endpoint c, copying the payload into b. It returns the number of // bytes copied into b, the control message cm and the source address // src of the received datagram. func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) { if !c.ok() { return 0, nil, nil, syscall.EINVAL } oob := newControlMessage(&c.rawOpt) var oobn int switch c := c.PacketConn.(type) { case *net.UDPConn: if n, oobn, _, src, err = c.ReadMsgUDP(b, oob); err != nil { return 0, nil, nil, err } case *net.IPConn: if n, oobn, _, src, err = c.ReadMsgIP(b, oob); err != nil { return 0, nil, nil, err } default: return 0, nil, nil, errInvalidConnType } if cm, err = parseControlMessage(oob[:oobn]); err != nil { return 0, nil, nil, err } if cm != nil { cm.Src = netAddrToIP16(src) } return } // WriteTo writes a payload of the IPv6 datagram, to the destination // address dst through the endpoint c, copying the payload from b. It // returns the number of bytes written. The control message cm allows // the IPv6 header fields and the datagram path to be specified. The // cm may be nil if control of the outgoing datagram is not required. func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) { if !c.ok() { return 0, syscall.EINVAL } oob := marshalControlMessage(cm) if dst == nil { return 0, errMissingAddress } switch c := c.PacketConn.(type) { case *net.UDPConn: n, _, err = c.WriteMsgUDP(b, oob, dst.(*net.UDPAddr)) case *net.IPConn: n, _, err = c.WriteMsgIP(b, oob, dst.(*net.IPAddr)) default: return 0, errInvalidConnType } if err != nil { return 0, err } return } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/payload_nocmsg.go000066400000000000000000000024331264464372400246540ustar00rootroot00000000000000// Copyright 2013 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. // +build nacl plan9 windows package ipv6 import ( "net" "syscall" ) // ReadFrom reads a payload of the received IPv6 datagram, from the // endpoint c, copying the payload into b. It returns the number of // bytes copied into b, the control message cm and the source address // src of the received datagram. func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) { if !c.ok() { return 0, nil, nil, syscall.EINVAL } if n, src, err = c.PacketConn.ReadFrom(b); err != nil { return 0, nil, nil, err } return } // WriteTo writes a payload of the IPv6 datagram, to the destination // address dst through the endpoint c, copying the payload from b. It // returns the number of bytes written. The control message cm allows // the IPv6 header fields and the datagram path to be specified. The // cm may be nil if control of the outgoing datagram is not required. func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) { if !c.ok() { return 0, syscall.EINVAL } if dst == nil { return 0, errMissingAddress } return c.PacketConn.WriteTo(b, dst) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/readwrite_test.go000066400000000000000000000103301264464372400246750ustar00rootroot00000000000000// Copyright 2013 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 ipv6_test import ( "bytes" "net" "runtime" "strings" "sync" "testing" "golang.org/x/net/internal/iana" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv6" ) func benchmarkUDPListener() (net.PacketConn, net.Addr, error) { c, err := net.ListenPacket("udp6", "[::1]:0") if err != nil { return nil, nil, err } dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String()) if err != nil { c.Close() return nil, nil, err } return c, dst, nil } func BenchmarkReadWriteNetUDP(b *testing.B) { if !supportsIPv6 { b.Skip("ipv6 is not supported") } c, dst, err := benchmarkUDPListener() if err != nil { b.Fatal(err) } defer c.Close() wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128) b.ResetTimer() for i := 0; i < b.N; i++ { benchmarkReadWriteNetUDP(b, c, wb, rb, dst) } } func benchmarkReadWriteNetUDP(b *testing.B, c net.PacketConn, wb, rb []byte, dst net.Addr) { if _, err := c.WriteTo(wb, dst); err != nil { b.Fatal(err) } if _, _, err := c.ReadFrom(rb); err != nil { b.Fatal(err) } } func BenchmarkReadWriteIPv6UDP(b *testing.B) { if !supportsIPv6 { b.Skip("ipv6 is not supported") } c, dst, err := benchmarkUDPListener() if err != nil { b.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU if err := p.SetControlMessage(cf, true); err != nil { b.Fatal(err) } ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback) wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128) b.ResetTimer() for i := 0; i < b.N; i++ { benchmarkReadWriteIPv6UDP(b, p, wb, rb, dst, ifi) } } func benchmarkReadWriteIPv6UDP(b *testing.B, p *ipv6.PacketConn, wb, rb []byte, dst net.Addr, ifi *net.Interface) { cm := ipv6.ControlMessage{ TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, HopLimit: 1, } if ifi != nil { cm.IfIndex = ifi.Index } if n, err := p.WriteTo(wb, &cm, dst); err != nil { b.Fatal(err) } else if n != len(wb) { b.Fatalf("got %v; want %v", n, len(wb)) } if _, _, _, err := p.ReadFrom(rb); err != nil { b.Fatal(err) } } func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } c, err := net.ListenPacket("udp6", "[::1]:0") if err != nil { t.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) defer p.Close() dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String()) if err != nil { t.Fatal(err) } ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback) cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU wb := []byte("HELLO-R-U-THERE") if err := p.SetControlMessage(cf, true); err != nil { // probe before test if nettest.ProtocolNotSupported(err) { t.Skipf("not supported on %s", runtime.GOOS) } t.Fatal(err) } var wg sync.WaitGroup reader := func() { defer wg.Done() rb := make([]byte, 128) if n, cm, _, err := p.ReadFrom(rb); err != nil { t.Error(err) return } else if !bytes.Equal(rb[:n], wb) { t.Errorf("got %v; want %v", rb[:n], wb) return } else { s := cm.String() if strings.Contains(s, ",") { t.Errorf("should be space-separated values: %s", s) } } } writer := func(toggle bool) { defer wg.Done() cm := ipv6.ControlMessage{ TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, Src: net.IPv6loopback, } if ifi != nil { cm.IfIndex = ifi.Index } if err := p.SetControlMessage(cf, toggle); err != nil { t.Error(err) return } if n, err := p.WriteTo(wb, &cm, dst); err != nil { t.Error(err) return } else if n != len(wb) { t.Errorf("got %v; want %v", n, len(wb)) return } } const N = 10 wg.Add(N) for i := 0; i < N; i++ { go reader() } wg.Add(2 * N) for i := 0; i < 2*N; i++ { go writer(i%2 != 0) } wg.Add(N) for i := 0; i < N; i++ { go reader() } wg.Wait() } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sockopt.go000066400000000000000000000035541264464372400233440ustar00rootroot00000000000000// Copyright 2014 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 ipv6 // Sticky socket options const ( ssoTrafficClass = iota // header field for unicast packet, RFC 3542 ssoHopLimit // header field for unicast packet, RFC 3493 ssoMulticastInterface // outbound interface for multicast packet, RFC 3493 ssoMulticastHopLimit // header field for multicast packet, RFC 3493 ssoMulticastLoopback // loopback for multicast packet, RFC 3493 ssoReceiveTrafficClass // header field on received packet, RFC 3542 ssoReceiveHopLimit // header field on received packet, RFC 2292 or 3542 ssoReceivePacketInfo // incbound or outbound packet path, RFC 2292 or 3542 ssoReceivePathMTU // path mtu, RFC 3542 ssoPathMTU // path mtu, RFC 3542 ssoChecksum // packet checksum, RFC 2292 or 3542 ssoICMPFilter // icmp filter, RFC 2292 or 3542 ssoJoinGroup // any-source multicast, RFC 3493 ssoLeaveGroup // any-source multicast, RFC 3493 ssoJoinSourceGroup // source-specific multicast ssoLeaveSourceGroup // source-specific multicast ssoBlockSourceGroup // any-source or source-specific multicast ssoUnblockSourceGroup // any-source or source-specific multicast ssoMax ) // Sticky socket option value types const ( ssoTypeInt = iota + 1 ssoTypeInterface ssoTypeICMPFilter ssoTypeMTUInfo ssoTypeIPMreq ssoTypeGroupReq ssoTypeGroupSourceReq ) // A sockOpt represents a binding for sticky socket option. type sockOpt struct { level int // option level name int // option name, must be equal or greater than 1 typ int // option value type, must be equal or greater than 1 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sockopt_asmreq_unix.go000066400000000000000000000010761264464372400257540ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin dragonfly freebsd linux netbsd openbsd package ipv6 import ( "net" "os" "unsafe" ) func setsockoptIPMreq(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error { var mreq sysIPv6Mreq copy(mreq.Multiaddr[:], grp) if ifi != nil { mreq.setIfindex(ifi.Index) } return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&mreq), sysSizeofIPv6Mreq)) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sockopt_asmreq_windows.go000066400000000000000000000010721264464372400264570ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import ( "net" "os" "syscall" "unsafe" ) func setsockoptIPMreq(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp net.IP) error { var mreq sysIPv6Mreq copy(mreq.Multiaddr[:], grp) if ifi != nil { mreq.setIfindex(ifi.Index) } return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&mreq)), sysSizeofIPv6Mreq)) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sockopt_ssmreq_stub.go000066400000000000000000000007111264464372400257630ustar00rootroot00000000000000// Copyright 2014 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. // +build !darwin,!freebsd,!linux package ipv6 import "net" func setsockoptGroupReq(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error { return errOpNoSupport } func setsockoptGroupSourceReq(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error { return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sockopt_ssmreq_unix.go000066400000000000000000000027101264464372400257720ustar00rootroot00000000000000// Copyright 2014 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. // +build darwin freebsd linux package ipv6 import ( "net" "os" "unsafe" ) var freebsd32o64 bool func setsockoptGroupReq(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error { var gr sysGroupReq if ifi != nil { gr.Interface = uint32(ifi.Index) } gr.setGroup(grp) var p unsafe.Pointer var l sysSockoptLen if freebsd32o64 { var d [sysSizeofGroupReq + 4]byte s := (*[sysSizeofGroupReq]byte)(unsafe.Pointer(&gr)) copy(d[:4], s[:4]) copy(d[8:], s[4:]) p = unsafe.Pointer(&d[0]) l = sysSizeofGroupReq + 4 } else { p = unsafe.Pointer(&gr) l = sysSizeofGroupReq } return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, p, l)) } func setsockoptGroupSourceReq(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error { var gsr sysGroupSourceReq if ifi != nil { gsr.Interface = uint32(ifi.Index) } gsr.setSourceGroup(grp, src) var p unsafe.Pointer var l sysSockoptLen if freebsd32o64 { var d [sysSizeofGroupSourceReq + 4]byte s := (*[sysSizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr)) copy(d[:4], s[:4]) copy(d[8:], s[4:]) p = unsafe.Pointer(&d[0]) l = sysSizeofGroupSourceReq + 4 } else { p = unsafe.Pointer(&gsr) l = sysSizeofGroupSourceReq } return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, p, l)) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sockopt_stub.go000066400000000000000000000005011264464372400243660ustar00rootroot00000000000000// Copyright 2013 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. // +build nacl plan9 solaris package ipv6 import "net" func getMTUInfo(fd int, opt *sockOpt) (*net.Interface, int, error) { return nil, 0, errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sockopt_test.go000066400000000000000000000056471264464372400244100ustar00rootroot00000000000000// Copyright 2013 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 ipv6_test import ( "fmt" "net" "runtime" "testing" "golang.org/x/net/internal/iana" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv6" ) var supportsIPv6 bool = nettest.SupportsIPv6() func TestConnInitiatorPathMTU(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } ln, err := net.Listen("tcp6", "[::1]:0") if err != nil { t.Fatal(err) } defer ln.Close() done := make(chan bool) go acceptor(t, ln, done) c, err := net.Dial("tcp6", ln.Addr().String()) if err != nil { t.Fatal(err) } defer c.Close() if pmtu, err := ipv6.NewConn(c).PathMTU(); err != nil { switch runtime.GOOS { case "darwin": // older darwin kernels don't support IPV6_PATHMTU option t.Logf("not supported on %s", runtime.GOOS) default: t.Fatal(err) } } else { t.Logf("path mtu for %v: %v", c.RemoteAddr(), pmtu) } <-done } func TestConnResponderPathMTU(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } ln, err := net.Listen("tcp6", "[::1]:0") if err != nil { t.Fatal(err) } defer ln.Close() done := make(chan bool) go connector(t, "tcp6", ln.Addr().String(), done) c, err := ln.Accept() if err != nil { t.Fatal(err) } defer c.Close() if pmtu, err := ipv6.NewConn(c).PathMTU(); err != nil { switch runtime.GOOS { case "darwin": // older darwin kernels don't support IPV6_PATHMTU option t.Logf("not supported on %s", runtime.GOOS) default: t.Fatal(err) } } else { t.Logf("path mtu for %v: %v", c.RemoteAddr(), pmtu) } <-done } func TestPacketConnChecksum(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } c, err := net.ListenPacket(fmt.Sprintf("ip6:%d", iana.ProtocolOSPFIGP), "::") // OSPF for IPv6 if err != nil { t.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) offset := 12 // see RFC 5340 for _, toggle := range []bool{false, true} { if err := p.SetChecksum(toggle, offset); err != nil { if toggle { t.Fatalf("ipv6.PacketConn.SetChecksum(%v, %v) failed: %v", toggle, offset, err) } else { // Some platforms never allow to disable the kernel // checksum processing. t.Logf("ipv6.PacketConn.SetChecksum(%v, %v) failed: %v", toggle, offset, err) } } if on, offset, err := p.Checksum(); err != nil { t.Fatal(err) } else { t.Logf("kernel checksum processing enabled=%v, offset=%v", on, offset) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sockopt_unix.go000066400000000000000000000064661264464372400244140ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin dragonfly freebsd linux netbsd openbsd package ipv6 import ( "net" "os" "unsafe" ) func getInt(fd int, opt *sockOpt) (int, error) { if opt.name < 1 || opt.typ != ssoTypeInt { return 0, errOpNoSupport } var i int32 l := sysSockoptLen(4) if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), &l); err != nil { return 0, os.NewSyscallError("getsockopt", err) } return int(i), nil } func setInt(fd int, opt *sockOpt, v int) error { if opt.name < 1 || opt.typ != ssoTypeInt { return errOpNoSupport } i := int32(v) return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), sysSockoptLen(4))) } func getInterface(fd int, opt *sockOpt) (*net.Interface, error) { if opt.name < 1 || opt.typ != ssoTypeInterface { return nil, errOpNoSupport } var i int32 l := sysSockoptLen(4) if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), &l); err != nil { return nil, os.NewSyscallError("getsockopt", err) } if i == 0 { return nil, nil } ifi, err := net.InterfaceByIndex(int(i)) if err != nil { return nil, err } return ifi, nil } func setInterface(fd int, opt *sockOpt, ifi *net.Interface) error { if opt.name < 1 || opt.typ != ssoTypeInterface { return errOpNoSupport } var i int32 if ifi != nil { i = int32(ifi.Index) } return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&i), sysSockoptLen(4))) } func getICMPFilter(fd int, opt *sockOpt) (*ICMPFilter, error) { if opt.name < 1 || opt.typ != ssoTypeICMPFilter { return nil, errOpNoSupport } var f ICMPFilter l := sysSockoptLen(sysSizeofICMPv6Filter) if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&f.sysICMPv6Filter), &l); err != nil { return nil, os.NewSyscallError("getsockopt", err) } return &f, nil } func setICMPFilter(fd int, opt *sockOpt, f *ICMPFilter) error { if opt.name < 1 || opt.typ != ssoTypeICMPFilter { return errOpNoSupport } return os.NewSyscallError("setsockopt", setsockopt(fd, opt.level, opt.name, unsafe.Pointer(&f.sysICMPv6Filter), sysSizeofICMPv6Filter)) } func getMTUInfo(fd int, opt *sockOpt) (*net.Interface, int, error) { if opt.name < 1 || opt.typ != ssoTypeMTUInfo { return nil, 0, errOpNoSupport } var mi sysIPv6Mtuinfo l := sysSockoptLen(sysSizeofIPv6Mtuinfo) if err := getsockopt(fd, opt.level, opt.name, unsafe.Pointer(&mi), &l); err != nil { return nil, 0, os.NewSyscallError("getsockopt", err) } if mi.Addr.Scope_id == 0 { return nil, int(mi.Mtu), nil } ifi, err := net.InterfaceByIndex(int(mi.Addr.Scope_id)) if err != nil { return nil, 0, err } return ifi, int(mi.Mtu), nil } func setGroup(fd int, opt *sockOpt, ifi *net.Interface, grp net.IP) error { if opt.name < 1 { return errOpNoSupport } switch opt.typ { case ssoTypeIPMreq: return setsockoptIPMreq(fd, opt, ifi, grp) case ssoTypeGroupReq: return setsockoptGroupReq(fd, opt, ifi, grp) default: return errOpNoSupport } } func setSourceGroup(fd int, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error { if opt.name < 1 || opt.typ != ssoTypeGroupSourceReq { return errOpNoSupport } return setsockoptGroupSourceReq(fd, opt, ifi, grp, src) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sockopt_windows.go000066400000000000000000000045131264464372400251120ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import ( "net" "os" "syscall" "unsafe" ) func getInt(fd syscall.Handle, opt *sockOpt) (int, error) { if opt.name < 1 || opt.typ != ssoTypeInt { return 0, errOpNoSupport } var i int32 l := int32(4) if err := syscall.Getsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), &l); err != nil { return 0, os.NewSyscallError("getsockopt", err) } return int(i), nil } func setInt(fd syscall.Handle, opt *sockOpt, v int) error { if opt.name < 1 || opt.typ != ssoTypeInt { return errOpNoSupport } i := int32(v) return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), 4)) } func getInterface(fd syscall.Handle, opt *sockOpt) (*net.Interface, error) { if opt.name < 1 || opt.typ != ssoTypeInterface { return nil, errOpNoSupport } var i int32 l := int32(4) if err := syscall.Getsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), &l); err != nil { return nil, os.NewSyscallError("getsockopt", err) } if i == 0 { return nil, nil } ifi, err := net.InterfaceByIndex(int(i)) if err != nil { return nil, err } return ifi, nil } func setInterface(fd syscall.Handle, opt *sockOpt, ifi *net.Interface) error { if opt.name < 1 || opt.typ != ssoTypeInterface { return errOpNoSupport } var i int32 if ifi != nil { i = int32(ifi.Index) } return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd, int32(opt.level), int32(opt.name), (*byte)(unsafe.Pointer(&i)), 4)) } func getICMPFilter(fd syscall.Handle, opt *sockOpt) (*ICMPFilter, error) { return nil, errOpNoSupport } func setICMPFilter(fd syscall.Handle, opt *sockOpt, f *ICMPFilter) error { return errOpNoSupport } func getMTUInfo(fd syscall.Handle, opt *sockOpt) (*net.Interface, int, error) { return nil, 0, errOpNoSupport } func setGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp net.IP) error { if opt.name < 1 || opt.typ != ssoTypeIPMreq { return errOpNoSupport } return setsockoptIPMreq(fd, opt, ifi, grp) } func setSourceGroup(fd syscall.Handle, opt *sockOpt, ifi *net.Interface, grp, src net.IP) error { // TODO(mikio): implement this return errOpNoSupport } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sys_bsd.go000066400000000000000000000043331264464372400233240ustar00rootroot00000000000000// Copyright 2013 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. // +build dragonfly netbsd openbsd package ipv6 import ( "net" "syscall" "golang.org/x/net/internal/iana" ) type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{ ctlTrafficClass: {sysIPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass}, ctlHopLimit: {sysIPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit}, ctlPacketInfo: {sysIPV6_PKTINFO, sysSizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo}, ctlNextHop: {sysIPV6_NEXTHOP, sysSizeofSockaddrInet6, marshalNextHop, parseNextHop}, ctlPathMTU: {sysIPV6_PATHMTU, sysSizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU}, } sockOpts = [ssoMax]sockOpt{ ssoTrafficClass: {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt}, ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt}, ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface}, ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt}, ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt}, ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt}, ssoReceiveHopLimit: {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt}, ssoReceivePacketInfo: {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt}, ssoReceivePathMTU: {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt}, ssoPathMTU: {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo}, ssoChecksum: {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt}, ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter}, ssoJoinGroup: {iana.ProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq}, ssoLeaveGroup: {iana.ProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq}, } ) func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) { sa.Len = sysSizeofSockaddrInet6 sa.Family = syscall.AF_INET6 copy(sa.Addr[:], ip) sa.Scope_id = uint32(i) } func (pi *sysInet6Pktinfo) setIfindex(i int) { pi.Ifindex = uint32(i) } func (mreq *sysIPv6Mreq) setIfindex(i int) { mreq.Interface = uint32(i) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sys_darwin.go000066400000000000000000000121501264464372400240340ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import ( "net" "syscall" "unsafe" "golang.org/x/net/internal/iana" ) type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{ ctlHopLimit: {sysIPV6_2292HOPLIMIT, 4, marshal2292HopLimit, parseHopLimit}, ctlPacketInfo: {sysIPV6_2292PKTINFO, sysSizeofInet6Pktinfo, marshal2292PacketInfo, parsePacketInfo}, } sockOpts = [ssoMax]sockOpt{ ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt}, ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface}, ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt}, ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt}, ssoReceiveHopLimit: {iana.ProtocolIPv6, sysIPV6_2292HOPLIMIT, ssoTypeInt}, ssoReceivePacketInfo: {iana.ProtocolIPv6, sysIPV6_2292PKTINFO, ssoTypeInt}, ssoChecksum: {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt}, ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter}, ssoJoinGroup: {iana.ProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq}, ssoLeaveGroup: {iana.ProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq}, } ) func init() { // Seems like kern.osreldate is veiled on latest OS X. We use // kern.osrelease instead. osver, err := syscall.Sysctl("kern.osrelease") if err != nil { return } var i int for i = range osver { if osver[i] == '.' { break } } // The IP_PKTINFO and protocol-independent multicast API were // introduced in OS X 10.7 (Darwin 11.0.0). But it looks like // those features require OS X 10.8 (Darwin 12.0.0) and above. // See http://support.apple.com/kb/HT1633. if i > 2 || i == 2 && osver[0] >= '1' && osver[1] >= '2' { ctlOpts[ctlTrafficClass].name = sysIPV6_TCLASS ctlOpts[ctlTrafficClass].length = 4 ctlOpts[ctlTrafficClass].marshal = marshalTrafficClass ctlOpts[ctlTrafficClass].parse = parseTrafficClass ctlOpts[ctlHopLimit].name = sysIPV6_HOPLIMIT ctlOpts[ctlHopLimit].marshal = marshalHopLimit ctlOpts[ctlPacketInfo].name = sysIPV6_PKTINFO ctlOpts[ctlPacketInfo].marshal = marshalPacketInfo ctlOpts[ctlNextHop].name = sysIPV6_NEXTHOP ctlOpts[ctlNextHop].length = sysSizeofSockaddrInet6 ctlOpts[ctlNextHop].marshal = marshalNextHop ctlOpts[ctlNextHop].parse = parseNextHop ctlOpts[ctlPathMTU].name = sysIPV6_PATHMTU ctlOpts[ctlPathMTU].length = sysSizeofIPv6Mtuinfo ctlOpts[ctlPathMTU].marshal = marshalPathMTU ctlOpts[ctlPathMTU].parse = parsePathMTU sockOpts[ssoTrafficClass].level = iana.ProtocolIPv6 sockOpts[ssoTrafficClass].name = sysIPV6_TCLASS sockOpts[ssoTrafficClass].typ = ssoTypeInt sockOpts[ssoReceiveTrafficClass].level = iana.ProtocolIPv6 sockOpts[ssoReceiveTrafficClass].name = sysIPV6_RECVTCLASS sockOpts[ssoReceiveTrafficClass].typ = ssoTypeInt sockOpts[ssoReceiveHopLimit].name = sysIPV6_RECVHOPLIMIT sockOpts[ssoReceivePacketInfo].name = sysIPV6_RECVPKTINFO sockOpts[ssoReceivePathMTU].level = iana.ProtocolIPv6 sockOpts[ssoReceivePathMTU].name = sysIPV6_RECVPATHMTU sockOpts[ssoReceivePathMTU].typ = ssoTypeInt sockOpts[ssoPathMTU].level = iana.ProtocolIPv6 sockOpts[ssoPathMTU].name = sysIPV6_PATHMTU sockOpts[ssoPathMTU].typ = ssoTypeMTUInfo sockOpts[ssoJoinGroup].name = sysMCAST_JOIN_GROUP sockOpts[ssoJoinGroup].typ = ssoTypeGroupReq sockOpts[ssoLeaveGroup].name = sysMCAST_LEAVE_GROUP sockOpts[ssoLeaveGroup].typ = ssoTypeGroupReq sockOpts[ssoJoinSourceGroup].level = iana.ProtocolIPv6 sockOpts[ssoJoinSourceGroup].name = sysMCAST_JOIN_SOURCE_GROUP sockOpts[ssoJoinSourceGroup].typ = ssoTypeGroupSourceReq sockOpts[ssoLeaveSourceGroup].level = iana.ProtocolIPv6 sockOpts[ssoLeaveSourceGroup].name = sysMCAST_LEAVE_SOURCE_GROUP sockOpts[ssoLeaveSourceGroup].typ = ssoTypeGroupSourceReq sockOpts[ssoBlockSourceGroup].level = iana.ProtocolIPv6 sockOpts[ssoBlockSourceGroup].name = sysMCAST_BLOCK_SOURCE sockOpts[ssoBlockSourceGroup].typ = ssoTypeGroupSourceReq sockOpts[ssoUnblockSourceGroup].level = iana.ProtocolIPv6 sockOpts[ssoUnblockSourceGroup].name = sysMCAST_UNBLOCK_SOURCE sockOpts[ssoUnblockSourceGroup].typ = ssoTypeGroupSourceReq } } func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) { sa.Len = sysSizeofSockaddrInet6 sa.Family = syscall.AF_INET6 copy(sa.Addr[:], ip) sa.Scope_id = uint32(i) } func (pi *sysInet6Pktinfo) setIfindex(i int) { pi.Ifindex = uint32(i) } func (mreq *sysIPv6Mreq) setIfindex(i int) { mreq.Interface = uint32(i) } func (gr *sysGroupReq) setGroup(grp net.IP) { sa := (*sysSockaddrInet6)(unsafe.Pointer(&gr.Pad_cgo_0[0])) sa.Len = sysSizeofSockaddrInet6 sa.Family = syscall.AF_INET6 copy(sa.Addr[:], grp) } func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) { sa := (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Pad_cgo_0[0])) sa.Len = sysSizeofSockaddrInet6 sa.Family = syscall.AF_INET6 copy(sa.Addr[:], grp) sa = (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Pad_cgo_1[0])) sa.Len = sysSizeofSockaddrInet6 sa.Family = syscall.AF_INET6 copy(sa.Addr[:], src) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sys_freebsd.go000066400000000000000000000065501264464372400241710ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import ( "net" "runtime" "strings" "syscall" "unsafe" "golang.org/x/net/internal/iana" ) type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{ ctlTrafficClass: {sysIPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass}, ctlHopLimit: {sysIPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit}, ctlPacketInfo: {sysIPV6_PKTINFO, sysSizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo}, ctlNextHop: {sysIPV6_NEXTHOP, sysSizeofSockaddrInet6, marshalNextHop, parseNextHop}, ctlPathMTU: {sysIPV6_PATHMTU, sysSizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU}, } sockOpts = [ssoMax]sockOpt{ ssoTrafficClass: {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt}, ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt}, ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface}, ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt}, ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt}, ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt}, ssoReceiveHopLimit: {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt}, ssoReceivePacketInfo: {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt}, ssoReceivePathMTU: {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt}, ssoPathMTU: {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo}, ssoChecksum: {iana.ProtocolIPv6, sysIPV6_CHECKSUM, ssoTypeInt}, ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMP6_FILTER, ssoTypeICMPFilter}, ssoJoinGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq}, ssoLeaveGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq}, ssoJoinSourceGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq}, ssoLeaveSourceGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq}, ssoBlockSourceGroup: {iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq}, ssoUnblockSourceGroup: {iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq}, } ) func init() { if runtime.GOOS == "freebsd" && runtime.GOARCH == "386" { archs, _ := syscall.Sysctl("kern.supported_archs") for _, s := range strings.Fields(archs) { if s == "amd64" { freebsd32o64 = true break } } } } func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) { sa.Len = sysSizeofSockaddrInet6 sa.Family = syscall.AF_INET6 copy(sa.Addr[:], ip) sa.Scope_id = uint32(i) } func (pi *sysInet6Pktinfo) setIfindex(i int) { pi.Ifindex = uint32(i) } func (mreq *sysIPv6Mreq) setIfindex(i int) { mreq.Interface = uint32(i) } func (gr *sysGroupReq) setGroup(grp net.IP) { sa := (*sysSockaddrInet6)(unsafe.Pointer(&gr.Group)) sa.Len = sysSizeofSockaddrInet6 sa.Family = syscall.AF_INET6 copy(sa.Addr[:], grp) } func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) { sa := (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Group)) sa.Len = sysSizeofSockaddrInet6 sa.Family = syscall.AF_INET6 copy(sa.Addr[:], grp) sa = (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Source)) sa.Len = sysSizeofSockaddrInet6 sa.Family = syscall.AF_INET6 copy(sa.Addr[:], src) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sys_linux.go000066400000000000000000000056031264464372400237140ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import ( "net" "syscall" "unsafe" "golang.org/x/net/internal/iana" ) type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{ ctlTrafficClass: {sysIPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass}, ctlHopLimit: {sysIPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit}, ctlPacketInfo: {sysIPV6_PKTINFO, sysSizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo}, ctlPathMTU: {sysIPV6_PATHMTU, sysSizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU}, } sockOpts = [ssoMax]sockOpt{ ssoTrafficClass: {iana.ProtocolIPv6, sysIPV6_TCLASS, ssoTypeInt}, ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt}, ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface}, ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt}, ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt}, ssoReceiveTrafficClass: {iana.ProtocolIPv6, sysIPV6_RECVTCLASS, ssoTypeInt}, ssoReceiveHopLimit: {iana.ProtocolIPv6, sysIPV6_RECVHOPLIMIT, ssoTypeInt}, ssoReceivePacketInfo: {iana.ProtocolIPv6, sysIPV6_RECVPKTINFO, ssoTypeInt}, ssoReceivePathMTU: {iana.ProtocolIPv6, sysIPV6_RECVPATHMTU, ssoTypeInt}, ssoPathMTU: {iana.ProtocolIPv6, sysIPV6_PATHMTU, ssoTypeMTUInfo}, ssoChecksum: {iana.ProtocolReserved, sysIPV6_CHECKSUM, ssoTypeInt}, ssoICMPFilter: {iana.ProtocolIPv6ICMP, sysICMPV6_FILTER, ssoTypeICMPFilter}, ssoJoinGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_GROUP, ssoTypeGroupReq}, ssoLeaveGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_GROUP, ssoTypeGroupReq}, ssoJoinSourceGroup: {iana.ProtocolIPv6, sysMCAST_JOIN_SOURCE_GROUP, ssoTypeGroupSourceReq}, ssoLeaveSourceGroup: {iana.ProtocolIPv6, sysMCAST_LEAVE_SOURCE_GROUP, ssoTypeGroupSourceReq}, ssoBlockSourceGroup: {iana.ProtocolIPv6, sysMCAST_BLOCK_SOURCE, ssoTypeGroupSourceReq}, ssoUnblockSourceGroup: {iana.ProtocolIPv6, sysMCAST_UNBLOCK_SOURCE, ssoTypeGroupSourceReq}, } ) func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) { sa.Family = syscall.AF_INET6 copy(sa.Addr[:], ip) sa.Scope_id = uint32(i) } func (pi *sysInet6Pktinfo) setIfindex(i int) { pi.Ifindex = int32(i) } func (mreq *sysIPv6Mreq) setIfindex(i int) { mreq.Ifindex = int32(i) } func (gr *sysGroupReq) setGroup(grp net.IP) { sa := (*sysSockaddrInet6)(unsafe.Pointer(&gr.Group)) sa.Family = syscall.AF_INET6 copy(sa.Addr[:], grp) } func (gsr *sysGroupSourceReq) setSourceGroup(grp, src net.IP) { sa := (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Group)) sa.Family = syscall.AF_INET6 copy(sa.Addr[:], grp) sa = (*sysSockaddrInet6)(unsafe.Pointer(&gsr.Source)) sa.Family = syscall.AF_INET6 copy(sa.Addr[:], src) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sys_stub.go000066400000000000000000000004511264464372400235260ustar00rootroot00000000000000// Copyright 2014 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. // +build nacl plan9 solaris package ipv6 type sysSockoptLen int32 var ( ctlOpts = [ctlMax]ctlOpt{} sockOpts = [ssoMax]sockOpt{} ) golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/sys_windows.go000066400000000000000000000030011264464372400242350ustar00rootroot00000000000000// Copyright 2013 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 ipv6 import ( "net" "syscall" "golang.org/x/net/internal/iana" ) const ( // See ws2tcpip.h. sysIPV6_UNICAST_HOPS = 0x4 sysIPV6_MULTICAST_IF = 0x9 sysIPV6_MULTICAST_HOPS = 0xa sysIPV6_MULTICAST_LOOP = 0xb sysIPV6_JOIN_GROUP = 0xc sysIPV6_LEAVE_GROUP = 0xd sysIPV6_PKTINFO = 0x13 sysSizeofSockaddrInet6 = 0x1c sysSizeofIPv6Mreq = 0x14 ) type sysSockaddrInet6 struct { Family uint16 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 } var ( ctlOpts = [ctlMax]ctlOpt{} sockOpts = [ssoMax]sockOpt{ ssoHopLimit: {iana.ProtocolIPv6, sysIPV6_UNICAST_HOPS, ssoTypeInt}, ssoMulticastInterface: {iana.ProtocolIPv6, sysIPV6_MULTICAST_IF, ssoTypeInterface}, ssoMulticastHopLimit: {iana.ProtocolIPv6, sysIPV6_MULTICAST_HOPS, ssoTypeInt}, ssoMulticastLoopback: {iana.ProtocolIPv6, sysIPV6_MULTICAST_LOOP, ssoTypeInt}, ssoJoinGroup: {iana.ProtocolIPv6, sysIPV6_JOIN_GROUP, ssoTypeIPMreq}, ssoLeaveGroup: {iana.ProtocolIPv6, sysIPV6_LEAVE_GROUP, ssoTypeIPMreq}, } ) func (sa *sysSockaddrInet6) setSockaddr(ip net.IP, i int) { sa.Family = syscall.AF_INET6 copy(sa.Addr[:], ip) sa.Scope_id = uint32(i) } func (mreq *sysIPv6Mreq) setIfindex(i int) { mreq.Interface = uint32(i) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/syscall_linux_386.go000066400000000000000000000015221264464372400251440ustar00rootroot00000000000000// 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 ipv6 import ( "syscall" "unsafe" ) const ( sysGETSOCKOPT = 0xf sysSETSOCKOPT = 0xe ) func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno) func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error { if _, errno := socketcall(sysGETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 { return error(errno) } return nil } func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error { if _, errno := socketcall(sysSETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 { return error(errno) } return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/syscall_unix.go000066400000000000000000000014601264464372400243710ustar00rootroot00000000000000// Copyright 2013 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. // +build darwin dragonfly freebsd linux,!386 netbsd openbsd package ipv6 import ( "syscall" "unsafe" ) func getsockopt(fd, level, name int, v unsafe.Pointer, l *sysSockoptLen) error { if _, _, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(unsafe.Pointer(l)), 0); errno != 0 { return error(errno) } return nil } func setsockopt(fd, level, name int, v unsafe.Pointer, l sysSockoptLen) error { if _, _, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(v), uintptr(l), 0); errno != 0 { return error(errno) } return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/thunk_linux_386.s000066400000000000000000000003541264464372400244620ustar00rootroot00000000000000// Copyright 2014 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. // +build go1.2 TEXT ·socketcall(SB),4,$0-36 JMP syscall·socketcall(SB) golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/unicast_test.go000066400000000000000000000112671264464372400243670ustar00rootroot00000000000000// Copyright 2013 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 ipv6_test import ( "bytes" "net" "os" "runtime" "testing" "time" "golang.org/x/net/icmp" "golang.org/x/net/internal/iana" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv6" ) func TestPacketConnReadWriteUnicastUDP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } c, err := net.ListenPacket("udp6", "[::1]:0") if err != nil { t.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) defer p.Close() dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String()) if err != nil { t.Fatal(err) } cm := ipv6.ControlMessage{ TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, Src: net.IPv6loopback, } cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback) if ifi != nil { cm.IfIndex = ifi.Index } wb := []byte("HELLO-R-U-THERE") for i, toggle := range []bool{true, false, true} { if err := p.SetControlMessage(cf, toggle); err != nil { if nettest.ProtocolNotSupported(err) { t.Skipf("not supported on %s", runtime.GOOS) } t.Fatal(err) } cm.HopLimit = i + 1 if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { t.Fatal(err) } if n, err := p.WriteTo(wb, &cm, dst); err != nil { t.Fatal(err) } else if n != len(wb) { t.Fatalf("got %v; want %v", n, len(wb)) } rb := make([]byte, 128) if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { t.Fatal(err) } if n, _, _, err := p.ReadFrom(rb); err != nil { t.Fatal(err) } else if !bytes.Equal(rb[:n], wb) { t.Fatalf("got %v; want %v", rb[:n], wb) } } } func TestPacketConnReadWriteUnicastICMP(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } if m, ok := nettest.SupportsRawIPSocket(); !ok { t.Skip(m) } c, err := net.ListenPacket("ip6:ipv6-icmp", "::1") if err != nil { t.Fatal(err) } defer c.Close() p := ipv6.NewPacketConn(c) defer p.Close() dst, err := net.ResolveIPAddr("ip6", "::1") if err != nil { t.Fatal(err) } pshicmp := icmp.IPv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP) cm := ipv6.ControlMessage{ TrafficClass: iana.DiffServAF11 | iana.CongestionExperienced, Src: net.IPv6loopback, } cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU ifi := nettest.RoutedInterface("ip6", net.FlagUp|net.FlagLoopback) if ifi != nil { cm.IfIndex = ifi.Index } var f ipv6.ICMPFilter f.SetAll(true) f.Accept(ipv6.ICMPTypeEchoReply) if err := p.SetICMPFilter(&f); err != nil { t.Fatal(err) } var psh []byte for i, toggle := range []bool{true, false, true} { if toggle { psh = nil if err := p.SetChecksum(true, 2); err != nil { t.Fatal(err) } } else { psh = pshicmp // Some platforms never allow to disable the // kernel checksum processing. p.SetChecksum(false, -1) } wb, err := (&icmp.Message{ Type: ipv6.ICMPTypeEchoRequest, Code: 0, Body: &icmp.Echo{ ID: os.Getpid() & 0xffff, Seq: i + 1, Data: []byte("HELLO-R-U-THERE"), }, }).Marshal(psh) if err != nil { t.Fatal(err) } if err := p.SetControlMessage(cf, toggle); err != nil { if nettest.ProtocolNotSupported(err) { t.Skipf("not supported on %s", runtime.GOOS) } t.Fatal(err) } cm.HopLimit = i + 1 if err := p.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { t.Fatal(err) } if n, err := p.WriteTo(wb, &cm, dst); err != nil { t.Fatal(err) } else if n != len(wb) { t.Fatalf("got %v; want %v", n, len(wb)) } rb := make([]byte, 128) if err := p.SetReadDeadline(time.Now().Add(100 * time.Millisecond)); err != nil { t.Fatal(err) } if n, _, _, err := p.ReadFrom(rb); err != nil { switch runtime.GOOS { case "darwin": // older darwin kernels have some limitation on receiving icmp packet through raw socket t.Logf("not supported on %s", runtime.GOOS) continue } t.Fatal(err) } else { if m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, rb[:n]); err != nil { t.Fatal(err) } else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 { t.Fatalf("got type=%v, code=%v; want type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0) } } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/unicastsockopt_test.go000066400000000000000000000045251264464372400257710ustar00rootroot00000000000000// Copyright 2013 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 ipv6_test import ( "net" "runtime" "testing" "golang.org/x/net/internal/iana" "golang.org/x/net/internal/nettest" "golang.org/x/net/ipv6" ) func TestConnUnicastSocketOptions(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } ln, err := net.Listen("tcp6", "[::1]:0") if err != nil { t.Fatal(err) } defer ln.Close() done := make(chan bool) go acceptor(t, ln, done) c, err := net.Dial("tcp6", ln.Addr().String()) if err != nil { t.Fatal(err) } defer c.Close() testUnicastSocketOptions(t, ipv6.NewConn(c)) <-done } var packetConnUnicastSocketOptionTests = []struct { net, proto, addr string }{ {"udp6", "", "[::1]:0"}, {"ip6", ":ipv6-icmp", "::1"}, } func TestPacketConnUnicastSocketOptions(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "solaris", "windows": t.Skipf("not supported on %s", runtime.GOOS) } if !supportsIPv6 { t.Skip("ipv6 is not supported") } m, ok := nettest.SupportsRawIPSocket() for _, tt := range packetConnUnicastSocketOptionTests { if tt.net == "ip6" && !ok { t.Log(m) continue } c, err := net.ListenPacket(tt.net+tt.proto, tt.addr) if err != nil { t.Fatal(err) } defer c.Close() testUnicastSocketOptions(t, ipv6.NewPacketConn(c)) } } type testIPv6UnicastConn interface { TrafficClass() (int, error) SetTrafficClass(int) error HopLimit() (int, error) SetHopLimit(int) error } func testUnicastSocketOptions(t *testing.T, c testIPv6UnicastConn) { tclass := iana.DiffServCS0 | iana.NotECNTransport if err := c.SetTrafficClass(tclass); err != nil { switch runtime.GOOS { case "darwin": // older darwin kernels don't support IPV6_TCLASS option t.Logf("not supported on %s", runtime.GOOS) goto next } t.Fatal(err) } if v, err := c.TrafficClass(); err != nil { t.Fatal(err) } else if v != tclass { t.Fatalf("got %v; want %v", v, tclass) } next: hoplim := 255 if err := c.SetHopLimit(hoplim); err != nil { t.Fatal(err) } if v, err := c.HopLimit(); err != nil { t.Fatal(err) } else if v != hoplim { t.Fatalf("got %v; want %v", v, hoplim) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_darwin.go000066400000000000000000000047631264464372400242410ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_darwin.go package ipv6 const ( sysIPV6_UNICAST_HOPS = 0x4 sysIPV6_MULTICAST_IF = 0x9 sysIPV6_MULTICAST_HOPS = 0xa sysIPV6_MULTICAST_LOOP = 0xb sysIPV6_JOIN_GROUP = 0xc sysIPV6_LEAVE_GROUP = 0xd sysIPV6_PORTRANGE = 0xe sysICMP6_FILTER = 0x12 sysIPV6_2292PKTINFO = 0x13 sysIPV6_2292HOPLIMIT = 0x14 sysIPV6_2292NEXTHOP = 0x15 sysIPV6_2292HOPOPTS = 0x16 sysIPV6_2292DSTOPTS = 0x17 sysIPV6_2292RTHDR = 0x18 sysIPV6_2292PKTOPTIONS = 0x19 sysIPV6_CHECKSUM = 0x1a sysIPV6_V6ONLY = 0x1b sysIPV6_IPSEC_POLICY = 0x1c sysIPV6_RECVTCLASS = 0x23 sysIPV6_TCLASS = 0x24 sysIPV6_RTHDRDSTOPTS = 0x39 sysIPV6_RECVPKTINFO = 0x3d sysIPV6_RECVHOPLIMIT = 0x25 sysIPV6_RECVRTHDR = 0x26 sysIPV6_RECVHOPOPTS = 0x27 sysIPV6_RECVDSTOPTS = 0x28 sysIPV6_USE_MIN_MTU = 0x2a sysIPV6_RECVPATHMTU = 0x2b sysIPV6_PATHMTU = 0x2c sysIPV6_PKTINFO = 0x2e sysIPV6_HOPLIMIT = 0x2f sysIPV6_NEXTHOP = 0x30 sysIPV6_HOPOPTS = 0x31 sysIPV6_DSTOPTS = 0x32 sysIPV6_RTHDR = 0x33 sysIPV6_AUTOFLOWLABEL = 0x3b sysIPV6_DONTFRAG = 0x3e sysIPV6_PREFER_TEMPADDR = 0x3f sysIPV6_MSFILTER = 0x4a sysMCAST_JOIN_GROUP = 0x50 sysMCAST_LEAVE_GROUP = 0x51 sysMCAST_JOIN_SOURCE_GROUP = 0x52 sysMCAST_LEAVE_SOURCE_GROUP = 0x53 sysMCAST_BLOCK_SOURCE = 0x54 sysMCAST_UNBLOCK_SOURCE = 0x55 sysIPV6_BOUND_IF = 0x7d sysIPV6_PORTRANGE_DEFAULT = 0x0 sysIPV6_PORTRANGE_HIGH = 0x1 sysIPV6_PORTRANGE_LOW = 0x2 sysSizeofSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x84 sysSizeofGroupSourceReq = 0x104 sysSizeofICMPv6Filter = 0x20 ) type sysSockaddrStorage struct { Len uint8 Family uint8 X__ss_pad1 [6]int8 X__ss_align int64 X__ss_pad2 [112]int8 } type sysSockaddrInet6 struct { Len uint8 Family uint8 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex uint32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 } type sysICMPv6Filter struct { Filt [8]uint32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [128]byte } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [128]byte Pad_cgo_1 [128]byte } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_dragonfly.go000066400000000000000000000032141264464372400247300ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_dragonfly.go // +build dragonfly package ipv6 const ( sysIPV6_UNICAST_HOPS = 0x4 sysIPV6_MULTICAST_IF = 0x9 sysIPV6_MULTICAST_HOPS = 0xa sysIPV6_MULTICAST_LOOP = 0xb sysIPV6_JOIN_GROUP = 0xc sysIPV6_LEAVE_GROUP = 0xd sysIPV6_PORTRANGE = 0xe sysICMP6_FILTER = 0x12 sysIPV6_CHECKSUM = 0x1a sysIPV6_V6ONLY = 0x1b sysIPV6_IPSEC_POLICY = 0x1c sysIPV6_RTHDRDSTOPTS = 0x23 sysIPV6_RECVPKTINFO = 0x24 sysIPV6_RECVHOPLIMIT = 0x25 sysIPV6_RECVRTHDR = 0x26 sysIPV6_RECVHOPOPTS = 0x27 sysIPV6_RECVDSTOPTS = 0x28 sysIPV6_USE_MIN_MTU = 0x2a sysIPV6_RECVPATHMTU = 0x2b sysIPV6_PATHMTU = 0x2c sysIPV6_PKTINFO = 0x2e sysIPV6_HOPLIMIT = 0x2f sysIPV6_NEXTHOP = 0x30 sysIPV6_HOPOPTS = 0x31 sysIPV6_DSTOPTS = 0x32 sysIPV6_RTHDR = 0x33 sysIPV6_RECVTCLASS = 0x39 sysIPV6_AUTOFLOWLABEL = 0x3b sysIPV6_TCLASS = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_PREFER_TEMPADDR = 0x3f sysIPV6_PORTRANGE_DEFAULT = 0x0 sysIPV6_PORTRANGE_HIGH = 0x1 sysIPV6_PORTRANGE_LOW = 0x2 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofICMPv6Filter = 0x20 ) type sysSockaddrInet6 struct { Len uint8 Family uint8 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex uint32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 } type sysICMPv6Filter struct { Filt [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_freebsd_386.go000066400000000000000000000044671264464372400247700ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_freebsd.go package ipv6 const ( sysIPV6_UNICAST_HOPS = 0x4 sysIPV6_MULTICAST_IF = 0x9 sysIPV6_MULTICAST_HOPS = 0xa sysIPV6_MULTICAST_LOOP = 0xb sysIPV6_JOIN_GROUP = 0xc sysIPV6_LEAVE_GROUP = 0xd sysIPV6_PORTRANGE = 0xe sysICMP6_FILTER = 0x12 sysIPV6_CHECKSUM = 0x1a sysIPV6_V6ONLY = 0x1b sysIPV6_IPSEC_POLICY = 0x1c sysIPV6_RTHDRDSTOPTS = 0x23 sysIPV6_RECVPKTINFO = 0x24 sysIPV6_RECVHOPLIMIT = 0x25 sysIPV6_RECVRTHDR = 0x26 sysIPV6_RECVHOPOPTS = 0x27 sysIPV6_RECVDSTOPTS = 0x28 sysIPV6_USE_MIN_MTU = 0x2a sysIPV6_RECVPATHMTU = 0x2b sysIPV6_PATHMTU = 0x2c sysIPV6_PKTINFO = 0x2e sysIPV6_HOPLIMIT = 0x2f sysIPV6_NEXTHOP = 0x30 sysIPV6_HOPOPTS = 0x31 sysIPV6_DSTOPTS = 0x32 sysIPV6_RTHDR = 0x33 sysIPV6_RECVTCLASS = 0x39 sysIPV6_AUTOFLOWLABEL = 0x3b sysIPV6_TCLASS = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_PREFER_TEMPADDR = 0x3f sysIPV6_BINDANY = 0x40 sysIPV6_MSFILTER = 0x4a sysMCAST_JOIN_GROUP = 0x50 sysMCAST_LEAVE_GROUP = 0x51 sysMCAST_JOIN_SOURCE_GROUP = 0x52 sysMCAST_LEAVE_SOURCE_GROUP = 0x53 sysMCAST_BLOCK_SOURCE = 0x54 sysMCAST_UNBLOCK_SOURCE = 0x55 sysIPV6_PORTRANGE_DEFAULT = 0x0 sysIPV6_PORTRANGE_HIGH = 0x1 sysIPV6_PORTRANGE_LOW = 0x2 sysSizeofSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x84 sysSizeofGroupSourceReq = 0x104 sysSizeofICMPv6Filter = 0x20 ) type sysSockaddrStorage struct { Len uint8 Family uint8 X__ss_pad1 [6]int8 X__ss_align int64 X__ss_pad2 [112]int8 } type sysSockaddrInet6 struct { Len uint8 Family uint8 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex uint32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 } type sysGroupReq struct { Interface uint32 Group sysSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Group sysSockaddrStorage Source sysSockaddrStorage } type sysICMPv6Filter struct { Filt [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_freebsd_amd64.go000066400000000000000000000045351264464372400253570ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_freebsd.go package ipv6 const ( sysIPV6_UNICAST_HOPS = 0x4 sysIPV6_MULTICAST_IF = 0x9 sysIPV6_MULTICAST_HOPS = 0xa sysIPV6_MULTICAST_LOOP = 0xb sysIPV6_JOIN_GROUP = 0xc sysIPV6_LEAVE_GROUP = 0xd sysIPV6_PORTRANGE = 0xe sysICMP6_FILTER = 0x12 sysIPV6_CHECKSUM = 0x1a sysIPV6_V6ONLY = 0x1b sysIPV6_IPSEC_POLICY = 0x1c sysIPV6_RTHDRDSTOPTS = 0x23 sysIPV6_RECVPKTINFO = 0x24 sysIPV6_RECVHOPLIMIT = 0x25 sysIPV6_RECVRTHDR = 0x26 sysIPV6_RECVHOPOPTS = 0x27 sysIPV6_RECVDSTOPTS = 0x28 sysIPV6_USE_MIN_MTU = 0x2a sysIPV6_RECVPATHMTU = 0x2b sysIPV6_PATHMTU = 0x2c sysIPV6_PKTINFO = 0x2e sysIPV6_HOPLIMIT = 0x2f sysIPV6_NEXTHOP = 0x30 sysIPV6_HOPOPTS = 0x31 sysIPV6_DSTOPTS = 0x32 sysIPV6_RTHDR = 0x33 sysIPV6_RECVTCLASS = 0x39 sysIPV6_AUTOFLOWLABEL = 0x3b sysIPV6_TCLASS = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_PREFER_TEMPADDR = 0x3f sysIPV6_BINDANY = 0x40 sysIPV6_MSFILTER = 0x4a sysMCAST_JOIN_GROUP = 0x50 sysMCAST_LEAVE_GROUP = 0x51 sysMCAST_JOIN_SOURCE_GROUP = 0x52 sysMCAST_LEAVE_SOURCE_GROUP = 0x53 sysMCAST_BLOCK_SOURCE = 0x54 sysMCAST_UNBLOCK_SOURCE = 0x55 sysIPV6_PORTRANGE_DEFAULT = 0x0 sysIPV6_PORTRANGE_HIGH = 0x1 sysIPV6_PORTRANGE_LOW = 0x2 sysSizeofSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPv6Filter = 0x20 ) type sysSockaddrStorage struct { Len uint8 Family uint8 X__ss_pad1 [6]int8 X__ss_align int64 X__ss_pad2 [112]int8 } type sysSockaddrInet6 struct { Len uint8 Family uint8 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex uint32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysSockaddrStorage Source sysSockaddrStorage } type sysICMPv6Filter struct { Filt [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_freebsd_arm.go000066400000000000000000000045351264464372400252230ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_freebsd.go package ipv6 const ( sysIPV6_UNICAST_HOPS = 0x4 sysIPV6_MULTICAST_IF = 0x9 sysIPV6_MULTICAST_HOPS = 0xa sysIPV6_MULTICAST_LOOP = 0xb sysIPV6_JOIN_GROUP = 0xc sysIPV6_LEAVE_GROUP = 0xd sysIPV6_PORTRANGE = 0xe sysICMP6_FILTER = 0x12 sysIPV6_CHECKSUM = 0x1a sysIPV6_V6ONLY = 0x1b sysIPV6_IPSEC_POLICY = 0x1c sysIPV6_RTHDRDSTOPTS = 0x23 sysIPV6_RECVPKTINFO = 0x24 sysIPV6_RECVHOPLIMIT = 0x25 sysIPV6_RECVRTHDR = 0x26 sysIPV6_RECVHOPOPTS = 0x27 sysIPV6_RECVDSTOPTS = 0x28 sysIPV6_USE_MIN_MTU = 0x2a sysIPV6_RECVPATHMTU = 0x2b sysIPV6_PATHMTU = 0x2c sysIPV6_PKTINFO = 0x2e sysIPV6_HOPLIMIT = 0x2f sysIPV6_NEXTHOP = 0x30 sysIPV6_HOPOPTS = 0x31 sysIPV6_DSTOPTS = 0x32 sysIPV6_RTHDR = 0x33 sysIPV6_RECVTCLASS = 0x39 sysIPV6_AUTOFLOWLABEL = 0x3b sysIPV6_TCLASS = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_PREFER_TEMPADDR = 0x3f sysIPV6_BINDANY = 0x40 sysIPV6_MSFILTER = 0x4a sysMCAST_JOIN_GROUP = 0x50 sysMCAST_LEAVE_GROUP = 0x51 sysMCAST_JOIN_SOURCE_GROUP = 0x52 sysMCAST_LEAVE_SOURCE_GROUP = 0x53 sysMCAST_BLOCK_SOURCE = 0x54 sysMCAST_UNBLOCK_SOURCE = 0x55 sysIPV6_PORTRANGE_DEFAULT = 0x0 sysIPV6_PORTRANGE_HIGH = 0x1 sysIPV6_PORTRANGE_LOW = 0x2 sysSizeofSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPv6Filter = 0x20 ) type sysSockaddrStorage struct { Len uint8 Family uint8 X__ss_pad1 [6]int8 X__ss_align int64 X__ss_pad2 [112]int8 } type sysSockaddrInet6 struct { Len uint8 Family uint8 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex uint32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysSockaddrStorage Source sysSockaddrStorage } type sysICMPv6Filter struct { Filt [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_linux_386.go000066400000000000000000000067761264464372400245220ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go package ipv6 const ( sysIPV6_ADDRFORM = 0x1 sysIPV6_2292PKTINFO = 0x2 sysIPV6_2292HOPOPTS = 0x3 sysIPV6_2292DSTOPTS = 0x4 sysIPV6_2292RTHDR = 0x5 sysIPV6_2292PKTOPTIONS = 0x6 sysIPV6_CHECKSUM = 0x7 sysIPV6_2292HOPLIMIT = 0x8 sysIPV6_NEXTHOP = 0x9 sysIPV6_FLOWINFO = 0xb sysIPV6_UNICAST_HOPS = 0x10 sysIPV6_MULTICAST_IF = 0x11 sysIPV6_MULTICAST_HOPS = 0x12 sysIPV6_MULTICAST_LOOP = 0x13 sysIPV6_ADD_MEMBERSHIP = 0x14 sysIPV6_DROP_MEMBERSHIP = 0x15 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIPV6_ROUTER_ALERT = 0x16 sysIPV6_MTU_DISCOVER = 0x17 sysIPV6_MTU = 0x18 sysIPV6_RECVERR = 0x19 sysIPV6_V6ONLY = 0x1a sysIPV6_JOIN_ANYCAST = 0x1b sysIPV6_LEAVE_ANYCAST = 0x1c sysIPV6_FLOWLABEL_MGR = 0x20 sysIPV6_FLOWINFO_SEND = 0x21 sysIPV6_IPSEC_POLICY = 0x22 sysIPV6_XFRM_POLICY = 0x23 sysIPV6_RECVPKTINFO = 0x31 sysIPV6_PKTINFO = 0x32 sysIPV6_RECVHOPLIMIT = 0x33 sysIPV6_HOPLIMIT = 0x34 sysIPV6_RECVHOPOPTS = 0x35 sysIPV6_HOPOPTS = 0x36 sysIPV6_RTHDRDSTOPTS = 0x37 sysIPV6_RECVRTHDR = 0x38 sysIPV6_RTHDR = 0x39 sysIPV6_RECVDSTOPTS = 0x3a sysIPV6_DSTOPTS = 0x3b sysIPV6_RECVPATHMTU = 0x3c sysIPV6_PATHMTU = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_RECVTCLASS = 0x42 sysIPV6_TCLASS = 0x43 sysIPV6_ADDR_PREFERENCES = 0x48 sysIPV6_PREFER_SRC_TMP = 0x1 sysIPV6_PREFER_SRC_PUBLIC = 0x2 sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = 0x100 sysIPV6_PREFER_SRC_COA = 0x4 sysIPV6_PREFER_SRC_HOME = 0x400 sysIPV6_PREFER_SRC_CGA = 0x8 sysIPV6_PREFER_SRC_NONCGA = 0x800 sysIPV6_MINHOPCOUNT = 0x49 sysIPV6_ORIGDSTADDR = 0x4a sysIPV6_RECVORIGDSTADDR = 0x4a sysIPV6_TRANSPARENT = 0x4b sysIPV6_UNICAST_IF = 0x4c sysICMPV6_FILTER = 0x1 sysICMPV6_FILTER_BLOCK = 0x1 sysICMPV6_FILTER_PASS = 0x2 sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6FlowlabelReq = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x84 sysSizeofGroupSourceReq = 0x104 sysSizeofICMPv6Filter = 0x20 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet6 struct { Family uint16 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex int32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6FlowlabelReq struct { Dst [16]byte /* in6_addr */ Label uint32 Action uint8 Share uint8 Flags uint16 Expires uint16 Linger uint16 X__flr_pad uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Ifindex int32 } type sysGroupReq struct { Interface uint32 Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPv6Filter struct { Data [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_linux_amd64.go000066400000000000000000000070441264464372400251020ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go package ipv6 const ( sysIPV6_ADDRFORM = 0x1 sysIPV6_2292PKTINFO = 0x2 sysIPV6_2292HOPOPTS = 0x3 sysIPV6_2292DSTOPTS = 0x4 sysIPV6_2292RTHDR = 0x5 sysIPV6_2292PKTOPTIONS = 0x6 sysIPV6_CHECKSUM = 0x7 sysIPV6_2292HOPLIMIT = 0x8 sysIPV6_NEXTHOP = 0x9 sysIPV6_FLOWINFO = 0xb sysIPV6_UNICAST_HOPS = 0x10 sysIPV6_MULTICAST_IF = 0x11 sysIPV6_MULTICAST_HOPS = 0x12 sysIPV6_MULTICAST_LOOP = 0x13 sysIPV6_ADD_MEMBERSHIP = 0x14 sysIPV6_DROP_MEMBERSHIP = 0x15 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIPV6_ROUTER_ALERT = 0x16 sysIPV6_MTU_DISCOVER = 0x17 sysIPV6_MTU = 0x18 sysIPV6_RECVERR = 0x19 sysIPV6_V6ONLY = 0x1a sysIPV6_JOIN_ANYCAST = 0x1b sysIPV6_LEAVE_ANYCAST = 0x1c sysIPV6_FLOWLABEL_MGR = 0x20 sysIPV6_FLOWINFO_SEND = 0x21 sysIPV6_IPSEC_POLICY = 0x22 sysIPV6_XFRM_POLICY = 0x23 sysIPV6_RECVPKTINFO = 0x31 sysIPV6_PKTINFO = 0x32 sysIPV6_RECVHOPLIMIT = 0x33 sysIPV6_HOPLIMIT = 0x34 sysIPV6_RECVHOPOPTS = 0x35 sysIPV6_HOPOPTS = 0x36 sysIPV6_RTHDRDSTOPTS = 0x37 sysIPV6_RECVRTHDR = 0x38 sysIPV6_RTHDR = 0x39 sysIPV6_RECVDSTOPTS = 0x3a sysIPV6_DSTOPTS = 0x3b sysIPV6_RECVPATHMTU = 0x3c sysIPV6_PATHMTU = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_RECVTCLASS = 0x42 sysIPV6_TCLASS = 0x43 sysIPV6_ADDR_PREFERENCES = 0x48 sysIPV6_PREFER_SRC_TMP = 0x1 sysIPV6_PREFER_SRC_PUBLIC = 0x2 sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = 0x100 sysIPV6_PREFER_SRC_COA = 0x4 sysIPV6_PREFER_SRC_HOME = 0x400 sysIPV6_PREFER_SRC_CGA = 0x8 sysIPV6_PREFER_SRC_NONCGA = 0x800 sysIPV6_MINHOPCOUNT = 0x49 sysIPV6_ORIGDSTADDR = 0x4a sysIPV6_RECVORIGDSTADDR = 0x4a sysIPV6_TRANSPARENT = 0x4b sysIPV6_UNICAST_IF = 0x4c sysICMPV6_FILTER = 0x1 sysICMPV6_FILTER_BLOCK = 0x1 sysICMPV6_FILTER_PASS = 0x2 sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6FlowlabelReq = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPv6Filter = 0x20 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet6 struct { Family uint16 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex int32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6FlowlabelReq struct { Dst [16]byte /* in6_addr */ Label uint32 Action uint8 Share uint8 Flags uint16 Expires uint16 Linger uint16 X__flr_pad uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Ifindex int32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPv6Filter struct { Data [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_linux_arm.go000066400000000000000000000067761264464372400247610ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go package ipv6 const ( sysIPV6_ADDRFORM = 0x1 sysIPV6_2292PKTINFO = 0x2 sysIPV6_2292HOPOPTS = 0x3 sysIPV6_2292DSTOPTS = 0x4 sysIPV6_2292RTHDR = 0x5 sysIPV6_2292PKTOPTIONS = 0x6 sysIPV6_CHECKSUM = 0x7 sysIPV6_2292HOPLIMIT = 0x8 sysIPV6_NEXTHOP = 0x9 sysIPV6_FLOWINFO = 0xb sysIPV6_UNICAST_HOPS = 0x10 sysIPV6_MULTICAST_IF = 0x11 sysIPV6_MULTICAST_HOPS = 0x12 sysIPV6_MULTICAST_LOOP = 0x13 sysIPV6_ADD_MEMBERSHIP = 0x14 sysIPV6_DROP_MEMBERSHIP = 0x15 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIPV6_ROUTER_ALERT = 0x16 sysIPV6_MTU_DISCOVER = 0x17 sysIPV6_MTU = 0x18 sysIPV6_RECVERR = 0x19 sysIPV6_V6ONLY = 0x1a sysIPV6_JOIN_ANYCAST = 0x1b sysIPV6_LEAVE_ANYCAST = 0x1c sysIPV6_FLOWLABEL_MGR = 0x20 sysIPV6_FLOWINFO_SEND = 0x21 sysIPV6_IPSEC_POLICY = 0x22 sysIPV6_XFRM_POLICY = 0x23 sysIPV6_RECVPKTINFO = 0x31 sysIPV6_PKTINFO = 0x32 sysIPV6_RECVHOPLIMIT = 0x33 sysIPV6_HOPLIMIT = 0x34 sysIPV6_RECVHOPOPTS = 0x35 sysIPV6_HOPOPTS = 0x36 sysIPV6_RTHDRDSTOPTS = 0x37 sysIPV6_RECVRTHDR = 0x38 sysIPV6_RTHDR = 0x39 sysIPV6_RECVDSTOPTS = 0x3a sysIPV6_DSTOPTS = 0x3b sysIPV6_RECVPATHMTU = 0x3c sysIPV6_PATHMTU = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_RECVTCLASS = 0x42 sysIPV6_TCLASS = 0x43 sysIPV6_ADDR_PREFERENCES = 0x48 sysIPV6_PREFER_SRC_TMP = 0x1 sysIPV6_PREFER_SRC_PUBLIC = 0x2 sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = 0x100 sysIPV6_PREFER_SRC_COA = 0x4 sysIPV6_PREFER_SRC_HOME = 0x400 sysIPV6_PREFER_SRC_CGA = 0x8 sysIPV6_PREFER_SRC_NONCGA = 0x800 sysIPV6_MINHOPCOUNT = 0x49 sysIPV6_ORIGDSTADDR = 0x4a sysIPV6_RECVORIGDSTADDR = 0x4a sysIPV6_TRANSPARENT = 0x4b sysIPV6_UNICAST_IF = 0x4c sysICMPV6_FILTER = 0x1 sysICMPV6_FILTER_BLOCK = 0x1 sysICMPV6_FILTER_PASS = 0x2 sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6FlowlabelReq = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x84 sysSizeofGroupSourceReq = 0x104 sysSizeofICMPv6Filter = 0x20 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet6 struct { Family uint16 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex int32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6FlowlabelReq struct { Dst [16]byte /* in6_addr */ Label uint32 Action uint8 Share uint8 Flags uint16 Expires uint16 Linger uint16 X__flr_pad uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Ifindex int32 } type sysGroupReq struct { Interface uint32 Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPv6Filter struct { Data [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_linux_arm64.go000066400000000000000000000070731264464372400251220ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go // +build linux,arm64 package ipv6 const ( sysIPV6_ADDRFORM = 0x1 sysIPV6_2292PKTINFO = 0x2 sysIPV6_2292HOPOPTS = 0x3 sysIPV6_2292DSTOPTS = 0x4 sysIPV6_2292RTHDR = 0x5 sysIPV6_2292PKTOPTIONS = 0x6 sysIPV6_CHECKSUM = 0x7 sysIPV6_2292HOPLIMIT = 0x8 sysIPV6_NEXTHOP = 0x9 sysIPV6_FLOWINFO = 0xb sysIPV6_UNICAST_HOPS = 0x10 sysIPV6_MULTICAST_IF = 0x11 sysIPV6_MULTICAST_HOPS = 0x12 sysIPV6_MULTICAST_LOOP = 0x13 sysIPV6_ADD_MEMBERSHIP = 0x14 sysIPV6_DROP_MEMBERSHIP = 0x15 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIPV6_ROUTER_ALERT = 0x16 sysIPV6_MTU_DISCOVER = 0x17 sysIPV6_MTU = 0x18 sysIPV6_RECVERR = 0x19 sysIPV6_V6ONLY = 0x1a sysIPV6_JOIN_ANYCAST = 0x1b sysIPV6_LEAVE_ANYCAST = 0x1c sysIPV6_FLOWLABEL_MGR = 0x20 sysIPV6_FLOWINFO_SEND = 0x21 sysIPV6_IPSEC_POLICY = 0x22 sysIPV6_XFRM_POLICY = 0x23 sysIPV6_RECVPKTINFO = 0x31 sysIPV6_PKTINFO = 0x32 sysIPV6_RECVHOPLIMIT = 0x33 sysIPV6_HOPLIMIT = 0x34 sysIPV6_RECVHOPOPTS = 0x35 sysIPV6_HOPOPTS = 0x36 sysIPV6_RTHDRDSTOPTS = 0x37 sysIPV6_RECVRTHDR = 0x38 sysIPV6_RTHDR = 0x39 sysIPV6_RECVDSTOPTS = 0x3a sysIPV6_DSTOPTS = 0x3b sysIPV6_RECVPATHMTU = 0x3c sysIPV6_PATHMTU = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_RECVTCLASS = 0x42 sysIPV6_TCLASS = 0x43 sysIPV6_ADDR_PREFERENCES = 0x48 sysIPV6_PREFER_SRC_TMP = 0x1 sysIPV6_PREFER_SRC_PUBLIC = 0x2 sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = 0x100 sysIPV6_PREFER_SRC_COA = 0x4 sysIPV6_PREFER_SRC_HOME = 0x400 sysIPV6_PREFER_SRC_CGA = 0x8 sysIPV6_PREFER_SRC_NONCGA = 0x800 sysIPV6_MINHOPCOUNT = 0x49 sysIPV6_ORIGDSTADDR = 0x4a sysIPV6_RECVORIGDSTADDR = 0x4a sysIPV6_TRANSPARENT = 0x4b sysIPV6_UNICAST_IF = 0x4c sysICMPV6_FILTER = 0x1 sysICMPV6_FILTER_BLOCK = 0x1 sysICMPV6_FILTER_PASS = 0x2 sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6FlowlabelReq = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPv6Filter = 0x20 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet6 struct { Family uint16 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex int32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6FlowlabelReq struct { Dst [16]byte /* in6_addr */ Label uint32 Action uint8 Share uint8 Flags uint16 Expires uint16 Linger uint16 X__flr_pad uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Ifindex int32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPv6Filter struct { Data [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_linux_mips64.go000066400000000000000000000070741264464372400253140ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go // +build linux,mips64 package ipv6 const ( sysIPV6_ADDRFORM = 0x1 sysIPV6_2292PKTINFO = 0x2 sysIPV6_2292HOPOPTS = 0x3 sysIPV6_2292DSTOPTS = 0x4 sysIPV6_2292RTHDR = 0x5 sysIPV6_2292PKTOPTIONS = 0x6 sysIPV6_CHECKSUM = 0x7 sysIPV6_2292HOPLIMIT = 0x8 sysIPV6_NEXTHOP = 0x9 sysIPV6_FLOWINFO = 0xb sysIPV6_UNICAST_HOPS = 0x10 sysIPV6_MULTICAST_IF = 0x11 sysIPV6_MULTICAST_HOPS = 0x12 sysIPV6_MULTICAST_LOOP = 0x13 sysIPV6_ADD_MEMBERSHIP = 0x14 sysIPV6_DROP_MEMBERSHIP = 0x15 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIPV6_ROUTER_ALERT = 0x16 sysIPV6_MTU_DISCOVER = 0x17 sysIPV6_MTU = 0x18 sysIPV6_RECVERR = 0x19 sysIPV6_V6ONLY = 0x1a sysIPV6_JOIN_ANYCAST = 0x1b sysIPV6_LEAVE_ANYCAST = 0x1c sysIPV6_FLOWLABEL_MGR = 0x20 sysIPV6_FLOWINFO_SEND = 0x21 sysIPV6_IPSEC_POLICY = 0x22 sysIPV6_XFRM_POLICY = 0x23 sysIPV6_RECVPKTINFO = 0x31 sysIPV6_PKTINFO = 0x32 sysIPV6_RECVHOPLIMIT = 0x33 sysIPV6_HOPLIMIT = 0x34 sysIPV6_RECVHOPOPTS = 0x35 sysIPV6_HOPOPTS = 0x36 sysIPV6_RTHDRDSTOPTS = 0x37 sysIPV6_RECVRTHDR = 0x38 sysIPV6_RTHDR = 0x39 sysIPV6_RECVDSTOPTS = 0x3a sysIPV6_DSTOPTS = 0x3b sysIPV6_RECVPATHMTU = 0x3c sysIPV6_PATHMTU = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_RECVTCLASS = 0x42 sysIPV6_TCLASS = 0x43 sysIPV6_ADDR_PREFERENCES = 0x48 sysIPV6_PREFER_SRC_TMP = 0x1 sysIPV6_PREFER_SRC_PUBLIC = 0x2 sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = 0x100 sysIPV6_PREFER_SRC_COA = 0x4 sysIPV6_PREFER_SRC_HOME = 0x400 sysIPV6_PREFER_SRC_CGA = 0x8 sysIPV6_PREFER_SRC_NONCGA = 0x800 sysIPV6_MINHOPCOUNT = 0x49 sysIPV6_ORIGDSTADDR = 0x4a sysIPV6_RECVORIGDSTADDR = 0x4a sysIPV6_TRANSPARENT = 0x4b sysIPV6_UNICAST_IF = 0x4c sysICMPV6_FILTER = 0x1 sysICMPV6_FILTER_BLOCK = 0x1 sysICMPV6_FILTER_PASS = 0x2 sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6FlowlabelReq = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPv6Filter = 0x20 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet6 struct { Family uint16 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex int32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6FlowlabelReq struct { Dst [16]byte /* in6_addr */ Label uint32 Action uint8 Share uint8 Flags uint16 Expires uint16 Linger uint16 X__flr_pad uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Ifindex int32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPv6Filter struct { Data [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_linux_mips64le.go000066400000000000000000000070761264464372400256370ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go // +build linux,mips64le package ipv6 const ( sysIPV6_ADDRFORM = 0x1 sysIPV6_2292PKTINFO = 0x2 sysIPV6_2292HOPOPTS = 0x3 sysIPV6_2292DSTOPTS = 0x4 sysIPV6_2292RTHDR = 0x5 sysIPV6_2292PKTOPTIONS = 0x6 sysIPV6_CHECKSUM = 0x7 sysIPV6_2292HOPLIMIT = 0x8 sysIPV6_NEXTHOP = 0x9 sysIPV6_FLOWINFO = 0xb sysIPV6_UNICAST_HOPS = 0x10 sysIPV6_MULTICAST_IF = 0x11 sysIPV6_MULTICAST_HOPS = 0x12 sysIPV6_MULTICAST_LOOP = 0x13 sysIPV6_ADD_MEMBERSHIP = 0x14 sysIPV6_DROP_MEMBERSHIP = 0x15 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIPV6_ROUTER_ALERT = 0x16 sysIPV6_MTU_DISCOVER = 0x17 sysIPV6_MTU = 0x18 sysIPV6_RECVERR = 0x19 sysIPV6_V6ONLY = 0x1a sysIPV6_JOIN_ANYCAST = 0x1b sysIPV6_LEAVE_ANYCAST = 0x1c sysIPV6_FLOWLABEL_MGR = 0x20 sysIPV6_FLOWINFO_SEND = 0x21 sysIPV6_IPSEC_POLICY = 0x22 sysIPV6_XFRM_POLICY = 0x23 sysIPV6_RECVPKTINFO = 0x31 sysIPV6_PKTINFO = 0x32 sysIPV6_RECVHOPLIMIT = 0x33 sysIPV6_HOPLIMIT = 0x34 sysIPV6_RECVHOPOPTS = 0x35 sysIPV6_HOPOPTS = 0x36 sysIPV6_RTHDRDSTOPTS = 0x37 sysIPV6_RECVRTHDR = 0x38 sysIPV6_RTHDR = 0x39 sysIPV6_RECVDSTOPTS = 0x3a sysIPV6_DSTOPTS = 0x3b sysIPV6_RECVPATHMTU = 0x3c sysIPV6_PATHMTU = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_RECVTCLASS = 0x42 sysIPV6_TCLASS = 0x43 sysIPV6_ADDR_PREFERENCES = 0x48 sysIPV6_PREFER_SRC_TMP = 0x1 sysIPV6_PREFER_SRC_PUBLIC = 0x2 sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = 0x100 sysIPV6_PREFER_SRC_COA = 0x4 sysIPV6_PREFER_SRC_HOME = 0x400 sysIPV6_PREFER_SRC_CGA = 0x8 sysIPV6_PREFER_SRC_NONCGA = 0x800 sysIPV6_MINHOPCOUNT = 0x49 sysIPV6_ORIGDSTADDR = 0x4a sysIPV6_RECVORIGDSTADDR = 0x4a sysIPV6_TRANSPARENT = 0x4b sysIPV6_UNICAST_IF = 0x4c sysICMPV6_FILTER = 0x1 sysICMPV6_FILTER_BLOCK = 0x1 sysICMPV6_FILTER_PASS = 0x2 sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6FlowlabelReq = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPv6Filter = 0x20 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet6 struct { Family uint16 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex int32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6FlowlabelReq struct { Dst [16]byte /* in6_addr */ Label uint32 Action uint8 Share uint8 Flags uint16 Expires uint16 Linger uint16 X__flr_pad uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Ifindex int32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPv6Filter struct { Data [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_linux_ppc64.go000066400000000000000000000070731264464372400251250ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go // +build linux,ppc64 package ipv6 const ( sysIPV6_ADDRFORM = 0x1 sysIPV6_2292PKTINFO = 0x2 sysIPV6_2292HOPOPTS = 0x3 sysIPV6_2292DSTOPTS = 0x4 sysIPV6_2292RTHDR = 0x5 sysIPV6_2292PKTOPTIONS = 0x6 sysIPV6_CHECKSUM = 0x7 sysIPV6_2292HOPLIMIT = 0x8 sysIPV6_NEXTHOP = 0x9 sysIPV6_FLOWINFO = 0xb sysIPV6_UNICAST_HOPS = 0x10 sysIPV6_MULTICAST_IF = 0x11 sysIPV6_MULTICAST_HOPS = 0x12 sysIPV6_MULTICAST_LOOP = 0x13 sysIPV6_ADD_MEMBERSHIP = 0x14 sysIPV6_DROP_MEMBERSHIP = 0x15 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIPV6_ROUTER_ALERT = 0x16 sysIPV6_MTU_DISCOVER = 0x17 sysIPV6_MTU = 0x18 sysIPV6_RECVERR = 0x19 sysIPV6_V6ONLY = 0x1a sysIPV6_JOIN_ANYCAST = 0x1b sysIPV6_LEAVE_ANYCAST = 0x1c sysIPV6_FLOWLABEL_MGR = 0x20 sysIPV6_FLOWINFO_SEND = 0x21 sysIPV6_IPSEC_POLICY = 0x22 sysIPV6_XFRM_POLICY = 0x23 sysIPV6_RECVPKTINFO = 0x31 sysIPV6_PKTINFO = 0x32 sysIPV6_RECVHOPLIMIT = 0x33 sysIPV6_HOPLIMIT = 0x34 sysIPV6_RECVHOPOPTS = 0x35 sysIPV6_HOPOPTS = 0x36 sysIPV6_RTHDRDSTOPTS = 0x37 sysIPV6_RECVRTHDR = 0x38 sysIPV6_RTHDR = 0x39 sysIPV6_RECVDSTOPTS = 0x3a sysIPV6_DSTOPTS = 0x3b sysIPV6_RECVPATHMTU = 0x3c sysIPV6_PATHMTU = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_RECVTCLASS = 0x42 sysIPV6_TCLASS = 0x43 sysIPV6_ADDR_PREFERENCES = 0x48 sysIPV6_PREFER_SRC_TMP = 0x1 sysIPV6_PREFER_SRC_PUBLIC = 0x2 sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = 0x100 sysIPV6_PREFER_SRC_COA = 0x4 sysIPV6_PREFER_SRC_HOME = 0x400 sysIPV6_PREFER_SRC_CGA = 0x8 sysIPV6_PREFER_SRC_NONCGA = 0x800 sysIPV6_MINHOPCOUNT = 0x49 sysIPV6_ORIGDSTADDR = 0x4a sysIPV6_RECVORIGDSTADDR = 0x4a sysIPV6_TRANSPARENT = 0x4b sysIPV6_UNICAST_IF = 0x4c sysICMPV6_FILTER = 0x1 sysICMPV6_FILTER_BLOCK = 0x1 sysICMPV6_FILTER_PASS = 0x2 sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6FlowlabelReq = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPv6Filter = 0x20 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet6 struct { Family uint16 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex int32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6FlowlabelReq struct { Dst [16]byte /* in6_addr */ Label uint32 Action uint8 Share uint8 Flags uint16 Expires uint16 Linger uint16 X__flr_pad uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Ifindex int32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPv6Filter struct { Data [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_linux_ppc64le.go000066400000000000000000000070751264464372400254500ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_linux.go // +build linux,ppc64le package ipv6 const ( sysIPV6_ADDRFORM = 0x1 sysIPV6_2292PKTINFO = 0x2 sysIPV6_2292HOPOPTS = 0x3 sysIPV6_2292DSTOPTS = 0x4 sysIPV6_2292RTHDR = 0x5 sysIPV6_2292PKTOPTIONS = 0x6 sysIPV6_CHECKSUM = 0x7 sysIPV6_2292HOPLIMIT = 0x8 sysIPV6_NEXTHOP = 0x9 sysIPV6_FLOWINFO = 0xb sysIPV6_UNICAST_HOPS = 0x10 sysIPV6_MULTICAST_IF = 0x11 sysIPV6_MULTICAST_HOPS = 0x12 sysIPV6_MULTICAST_LOOP = 0x13 sysIPV6_ADD_MEMBERSHIP = 0x14 sysIPV6_DROP_MEMBERSHIP = 0x15 sysMCAST_JOIN_GROUP = 0x2a sysMCAST_LEAVE_GROUP = 0x2d sysMCAST_JOIN_SOURCE_GROUP = 0x2e sysMCAST_LEAVE_SOURCE_GROUP = 0x2f sysMCAST_BLOCK_SOURCE = 0x2b sysMCAST_UNBLOCK_SOURCE = 0x2c sysMCAST_MSFILTER = 0x30 sysIPV6_ROUTER_ALERT = 0x16 sysIPV6_MTU_DISCOVER = 0x17 sysIPV6_MTU = 0x18 sysIPV6_RECVERR = 0x19 sysIPV6_V6ONLY = 0x1a sysIPV6_JOIN_ANYCAST = 0x1b sysIPV6_LEAVE_ANYCAST = 0x1c sysIPV6_FLOWLABEL_MGR = 0x20 sysIPV6_FLOWINFO_SEND = 0x21 sysIPV6_IPSEC_POLICY = 0x22 sysIPV6_XFRM_POLICY = 0x23 sysIPV6_RECVPKTINFO = 0x31 sysIPV6_PKTINFO = 0x32 sysIPV6_RECVHOPLIMIT = 0x33 sysIPV6_HOPLIMIT = 0x34 sysIPV6_RECVHOPOPTS = 0x35 sysIPV6_HOPOPTS = 0x36 sysIPV6_RTHDRDSTOPTS = 0x37 sysIPV6_RECVRTHDR = 0x38 sysIPV6_RTHDR = 0x39 sysIPV6_RECVDSTOPTS = 0x3a sysIPV6_DSTOPTS = 0x3b sysIPV6_RECVPATHMTU = 0x3c sysIPV6_PATHMTU = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_RECVTCLASS = 0x42 sysIPV6_TCLASS = 0x43 sysIPV6_ADDR_PREFERENCES = 0x48 sysIPV6_PREFER_SRC_TMP = 0x1 sysIPV6_PREFER_SRC_PUBLIC = 0x2 sysIPV6_PREFER_SRC_PUBTMP_DEFAULT = 0x100 sysIPV6_PREFER_SRC_COA = 0x4 sysIPV6_PREFER_SRC_HOME = 0x400 sysIPV6_PREFER_SRC_CGA = 0x8 sysIPV6_PREFER_SRC_NONCGA = 0x800 sysIPV6_MINHOPCOUNT = 0x49 sysIPV6_ORIGDSTADDR = 0x4a sysIPV6_RECVORIGDSTADDR = 0x4a sysIPV6_TRANSPARENT = 0x4b sysIPV6_UNICAST_IF = 0x4c sysICMPV6_FILTER = 0x1 sysICMPV6_FILTER_BLOCK = 0x1 sysICMPV6_FILTER_PASS = 0x2 sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6FlowlabelReq = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofGroupReq = 0x88 sysSizeofGroupSourceReq = 0x108 sysSizeofICMPv6Filter = 0x20 ) type sysKernelSockaddrStorage struct { Family uint16 X__data [126]int8 } type sysSockaddrInet6 struct { Family uint16 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex int32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6FlowlabelReq struct { Dst [16]byte /* in6_addr */ Label uint32 Action uint8 Share uint8 Flags uint16 Expires uint16 Linger uint16 X__flr_pad uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Ifindex int32 } type sysGroupReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage } type sysGroupSourceReq struct { Interface uint32 Pad_cgo_0 [4]byte Group sysKernelSockaddrStorage Source sysKernelSockaddrStorage } type sysICMPv6Filter struct { Data [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_netbsd.go000066400000000000000000000030701264464372400242220ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_netbsd.go package ipv6 const ( sysIPV6_UNICAST_HOPS = 0x4 sysIPV6_MULTICAST_IF = 0x9 sysIPV6_MULTICAST_HOPS = 0xa sysIPV6_MULTICAST_LOOP = 0xb sysIPV6_JOIN_GROUP = 0xc sysIPV6_LEAVE_GROUP = 0xd sysIPV6_PORTRANGE = 0xe sysICMP6_FILTER = 0x12 sysIPV6_CHECKSUM = 0x1a sysIPV6_V6ONLY = 0x1b sysIPV6_IPSEC_POLICY = 0x1c sysIPV6_RTHDRDSTOPTS = 0x23 sysIPV6_RECVPKTINFO = 0x24 sysIPV6_RECVHOPLIMIT = 0x25 sysIPV6_RECVRTHDR = 0x26 sysIPV6_RECVHOPOPTS = 0x27 sysIPV6_RECVDSTOPTS = 0x28 sysIPV6_USE_MIN_MTU = 0x2a sysIPV6_RECVPATHMTU = 0x2b sysIPV6_PATHMTU = 0x2c sysIPV6_PKTINFO = 0x2e sysIPV6_HOPLIMIT = 0x2f sysIPV6_NEXTHOP = 0x30 sysIPV6_HOPOPTS = 0x31 sysIPV6_DSTOPTS = 0x32 sysIPV6_RTHDR = 0x33 sysIPV6_RECVTCLASS = 0x39 sysIPV6_TCLASS = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_PORTRANGE_DEFAULT = 0x0 sysIPV6_PORTRANGE_HIGH = 0x1 sysIPV6_PORTRANGE_LOW = 0x2 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofICMPv6Filter = 0x20 ) type sysSockaddrInet6 struct { Len uint8 Family uint8 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex uint32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 } type sysICMPv6Filter struct { Filt [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_openbsd.go000066400000000000000000000034271264464372400244030ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_openbsd.go package ipv6 const ( sysIPV6_UNICAST_HOPS = 0x4 sysIPV6_MULTICAST_IF = 0x9 sysIPV6_MULTICAST_HOPS = 0xa sysIPV6_MULTICAST_LOOP = 0xb sysIPV6_JOIN_GROUP = 0xc sysIPV6_LEAVE_GROUP = 0xd sysIPV6_PORTRANGE = 0xe sysICMP6_FILTER = 0x12 sysIPV6_CHECKSUM = 0x1a sysIPV6_V6ONLY = 0x1b sysIPV6_RTHDRDSTOPTS = 0x23 sysIPV6_RECVPKTINFO = 0x24 sysIPV6_RECVHOPLIMIT = 0x25 sysIPV6_RECVRTHDR = 0x26 sysIPV6_RECVHOPOPTS = 0x27 sysIPV6_RECVDSTOPTS = 0x28 sysIPV6_USE_MIN_MTU = 0x2a sysIPV6_RECVPATHMTU = 0x2b sysIPV6_PATHMTU = 0x2c sysIPV6_PKTINFO = 0x2e sysIPV6_HOPLIMIT = 0x2f sysIPV6_NEXTHOP = 0x30 sysIPV6_HOPOPTS = 0x31 sysIPV6_DSTOPTS = 0x32 sysIPV6_RTHDR = 0x33 sysIPV6_AUTH_LEVEL = 0x35 sysIPV6_ESP_TRANS_LEVEL = 0x36 sysIPV6_ESP_NETWORK_LEVEL = 0x37 sysIPSEC6_OUTSA = 0x38 sysIPV6_RECVTCLASS = 0x39 sysIPV6_AUTOFLOWLABEL = 0x3b sysIPV6_IPCOMP_LEVEL = 0x3c sysIPV6_TCLASS = 0x3d sysIPV6_DONTFRAG = 0x3e sysIPV6_PIPEX = 0x3f sysIPV6_RTABLE = 0x1021 sysIPV6_PORTRANGE_DEFAULT = 0x0 sysIPV6_PORTRANGE_HIGH = 0x1 sysIPV6_PORTRANGE_LOW = 0x2 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x20 sysSizeofIPv6Mreq = 0x14 sysSizeofICMPv6Filter = 0x20 ) type sysSockaddrInet6 struct { Len uint8 Family uint8 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex uint32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 } type sysICMPv6Filter struct { Filt [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/ipv6/zsys_solaris.go000066400000000000000000000042031264464372400244160ustar00rootroot00000000000000// Created by cgo -godefs - DO NOT EDIT // cgo -godefs defs_solaris.go // +build solaris package ipv6 const ( sysIPV6_UNICAST_HOPS = 0x5 sysIPV6_MULTICAST_IF = 0x6 sysIPV6_MULTICAST_HOPS = 0x7 sysIPV6_MULTICAST_LOOP = 0x8 sysIPV6_JOIN_GROUP = 0x9 sysIPV6_LEAVE_GROUP = 0xa sysIPV6_PKTINFO = 0xb sysIPV6_HOPLIMIT = 0xc sysIPV6_NEXTHOP = 0xd sysIPV6_HOPOPTS = 0xe sysIPV6_DSTOPTS = 0xf sysIPV6_RTHDR = 0x10 sysIPV6_RTHDRDSTOPTS = 0x11 sysIPV6_RECVPKTINFO = 0x12 sysIPV6_RECVHOPLIMIT = 0x13 sysIPV6_RECVHOPOPTS = 0x14 sysIPV6_RECVRTHDR = 0x16 sysIPV6_RECVRTHDRDSTOPTS = 0x17 sysIPV6_CHECKSUM = 0x18 sysIPV6_RECVTCLASS = 0x19 sysIPV6_USE_MIN_MTU = 0x20 sysIPV6_DONTFRAG = 0x21 sysIPV6_SEC_OPT = 0x22 sysIPV6_SRC_PREFERENCES = 0x23 sysIPV6_RECVPATHMTU = 0x24 sysIPV6_PATHMTU = 0x25 sysIPV6_TCLASS = 0x26 sysIPV6_V6ONLY = 0x27 sysIPV6_RECVDSTOPTS = 0x28 sysIPV6_PREFER_SRC_HOME = 0x1 sysIPV6_PREFER_SRC_COA = 0x2 sysIPV6_PREFER_SRC_PUBLIC = 0x4 sysIPV6_PREFER_SRC_TMP = 0x8 sysIPV6_PREFER_SRC_NONCGA = 0x10 sysIPV6_PREFER_SRC_CGA = 0x20 sysIPV6_PREFER_SRC_MIPMASK = 0x3 sysIPV6_PREFER_SRC_MIPDEFAULT = 0x1 sysIPV6_PREFER_SRC_TMPMASK = 0xc sysIPV6_PREFER_SRC_TMPDEFAULT = 0x4 sysIPV6_PREFER_SRC_CGAMASK = 0x30 sysIPV6_PREFER_SRC_CGADEFAULT = 0x10 sysIPV6_PREFER_SRC_MASK = 0x3f sysIPV6_PREFER_SRC_DEFAULT = 0x15 sysIPV6_BOUND_IF = 0x41 sysIPV6_UNSPEC_SRC = 0x42 sysICMP6_FILTER = 0x1 sysSizeofSockaddrInet6 = 0x20 sysSizeofInet6Pktinfo = 0x14 sysSizeofIPv6Mtuinfo = 0x24 sysSizeofIPv6Mreq = 0x14 sysSizeofICMPv6Filter = 0x20 ) type sysSockaddrInet6 struct { Family uint16 Port uint16 Flowinfo uint32 Addr [16]byte /* in6_addr */ Scope_id uint32 X__sin6_src_id uint32 } type sysInet6Pktinfo struct { Addr [16]byte /* in6_addr */ Ifindex uint32 } type sysIPv6Mtuinfo struct { Addr sysSockaddrInet6 Mtu uint32 } type sysIPv6Mreq struct { Multiaddr [16]byte /* in6_addr */ Interface uint32 } type sysICMPv6Filter struct { X__icmp6_filt [8]uint32 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/netutil/000077500000000000000000000000001264464372400221245ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/netutil/listen.go000066400000000000000000000022101264464372400237440ustar00rootroot00000000000000// Copyright 2013 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 netutil provides network utility functions, complementing the more // common ones in the net package. package netutil // import "golang.org/x/net/netutil" import ( "net" "sync" ) // LimitListener returns a Listener that accepts at most n simultaneous // connections from the provided Listener. func LimitListener(l net.Listener, n int) net.Listener { return &limitListener{l, make(chan struct{}, n)} } type limitListener struct { net.Listener sem chan struct{} } func (l *limitListener) acquire() { l.sem <- struct{}{} } func (l *limitListener) release() { <-l.sem } func (l *limitListener) Accept() (net.Conn, error) { l.acquire() c, err := l.Listener.Accept() if err != nil { l.release() return nil, err } return &limitListenerConn{Conn: c, release: l.release}, nil } type limitListenerConn struct { net.Conn releaseOnce sync.Once release func() } func (l *limitListenerConn) Close() error { err := l.Conn.Close() l.releaseOnce.Do(l.release) return err } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/netutil/listen_test.go000066400000000000000000000041361264464372400250140ustar00rootroot00000000000000// Copyright 2013 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 netutil import ( "errors" "fmt" "io" "io/ioutil" "net" "net/http" "sync" "sync/atomic" "testing" "time" "golang.org/x/net/internal/nettest" ) func TestLimitListener(t *testing.T) { const max = 5 attempts := (nettest.MaxOpenFiles() - max) / 2 if attempts > 256 { // maximum length of accept queue is 128 by default attempts = 256 } l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatal(err) } defer l.Close() l = LimitListener(l, max) var open int32 go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if n := atomic.AddInt32(&open, 1); n > max { t.Errorf("%d open connections, want <= %d", n, max) } defer atomic.AddInt32(&open, -1) time.Sleep(10 * time.Millisecond) fmt.Fprint(w, "some body") })) var wg sync.WaitGroup var failed int32 for i := 0; i < attempts; i++ { wg.Add(1) go func() { defer wg.Done() c := http.Client{Timeout: 3 * time.Second} r, err := c.Get("http://" + l.Addr().String()) if err != nil { t.Log(err) atomic.AddInt32(&failed, 1) return } defer r.Body.Close() io.Copy(ioutil.Discard, r.Body) }() } wg.Wait() // We expect some Gets to fail as the kernel's accept queue is filled, // but most should succeed. if int(failed) >= attempts/2 { t.Errorf("%d requests failed within %d attempts", failed, attempts) } } type errorListener struct { net.Listener } func (errorListener) Accept() (net.Conn, error) { return nil, errFake } var errFake = errors.New("fake error from errorListener") // This used to hang. func TestLimitListenerError(t *testing.T) { donec := make(chan bool, 1) go func() { const n = 2 ll := LimitListener(errorListener{}, n) for i := 0; i < n+1; i++ { _, err := ll.Accept() if err != errFake { t.Fatalf("Accept error = %v; want errFake", err) } } donec <- true }() select { case <-donec: case <-time.After(5 * time.Second): t.Fatal("timeout. deadlock?") } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/proxy/000077500000000000000000000000001264464372400216215ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/proxy/direct.go000066400000000000000000000006301264464372400234210ustar00rootroot00000000000000// 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 proxy import ( "net" ) type direct struct{} // Direct is a direct proxy: one that makes network connections directly. var Direct = direct{} func (direct) Dial(network, addr string) (net.Conn, error) { return net.Dial(network, addr) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/proxy/per_host.go000066400000000000000000000071741264464372400240040ustar00rootroot00000000000000// 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 proxy import ( "net" "strings" ) // A PerHost directs connections to a default Dialer unless the hostname // requested matches one of a number of exceptions. type PerHost struct { def, bypass Dialer bypassNetworks []*net.IPNet bypassIPs []net.IP bypassZones []string bypassHosts []string } // NewPerHost returns a PerHost Dialer that directs connections to either // defaultDialer or bypass, depending on whether the connection matches one of // the configured rules. func NewPerHost(defaultDialer, bypass Dialer) *PerHost { return &PerHost{ def: defaultDialer, bypass: bypass, } } // Dial connects to the address addr on the given network through either // defaultDialer or bypass. func (p *PerHost) Dial(network, addr string) (c net.Conn, err error) { host, _, err := net.SplitHostPort(addr) if err != nil { return nil, err } return p.dialerForRequest(host).Dial(network, addr) } func (p *PerHost) dialerForRequest(host string) Dialer { if ip := net.ParseIP(host); ip != nil { for _, net := range p.bypassNetworks { if net.Contains(ip) { return p.bypass } } for _, bypassIP := range p.bypassIPs { if bypassIP.Equal(ip) { return p.bypass } } return p.def } for _, zone := range p.bypassZones { if strings.HasSuffix(host, zone) { return p.bypass } if host == zone[1:] { // For a zone "example.com", we match "example.com" // too. return p.bypass } } for _, bypassHost := range p.bypassHosts { if bypassHost == host { return p.bypass } } return p.def } // AddFromString parses a string that contains comma-separated values // specifying hosts that should use the bypass proxy. Each value is either an // IP address, a CIDR range, a zone (*.example.com) or a hostname // (localhost). A best effort is made to parse the string and errors are // ignored. func (p *PerHost) AddFromString(s string) { hosts := strings.Split(s, ",") for _, host := range hosts { host = strings.TrimSpace(host) if len(host) == 0 { continue } if strings.Contains(host, "/") { // We assume that it's a CIDR address like 127.0.0.0/8 if _, net, err := net.ParseCIDR(host); err == nil { p.AddNetwork(net) } continue } if ip := net.ParseIP(host); ip != nil { p.AddIP(ip) continue } if strings.HasPrefix(host, "*.") { p.AddZone(host[1:]) continue } p.AddHost(host) } } // AddIP specifies an IP address that will use the bypass proxy. Note that // this will only take effect if a literal IP address is dialed. A connection // to a named host will never match an IP. func (p *PerHost) AddIP(ip net.IP) { p.bypassIPs = append(p.bypassIPs, ip) } // AddNetwork specifies an IP range that will use the bypass proxy. Note that // this will only take effect if a literal IP address is dialed. A connection // to a named host will never match. func (p *PerHost) AddNetwork(net *net.IPNet) { p.bypassNetworks = append(p.bypassNetworks, net) } // AddZone specifies a DNS suffix that will use the bypass proxy. A zone of // "example.com" matches "example.com" and all of its subdomains. func (p *PerHost) AddZone(zone string) { if strings.HasSuffix(zone, ".") { zone = zone[:len(zone)-1] } if !strings.HasPrefix(zone, ".") { zone = "." + zone } p.bypassZones = append(p.bypassZones, zone) } // AddHost specifies a hostname that will use the bypass proxy. func (p *PerHost) AddHost(host string) { if strings.HasSuffix(host, ".") { host = host[:len(host)-1] } p.bypassHosts = append(p.bypassHosts, host) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/proxy/per_host_test.go000066400000000000000000000024151264464372400250340ustar00rootroot00000000000000// 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 proxy import ( "errors" "net" "reflect" "testing" ) type recordingProxy struct { addrs []string } func (r *recordingProxy) Dial(network, addr string) (net.Conn, error) { r.addrs = append(r.addrs, addr) return nil, errors.New("recordingProxy") } func TestPerHost(t *testing.T) { var def, bypass recordingProxy perHost := NewPerHost(&def, &bypass) perHost.AddFromString("localhost,*.zone,127.0.0.1,10.0.0.1/8,1000::/16") expectedDef := []string{ "example.com:123", "1.2.3.4:123", "[1001::]:123", } expectedBypass := []string{ "localhost:123", "zone:123", "foo.zone:123", "127.0.0.1:123", "10.1.2.3:123", "[1000::]:123", } for _, addr := range expectedDef { perHost.Dial("tcp", addr) } for _, addr := range expectedBypass { perHost.Dial("tcp", addr) } if !reflect.DeepEqual(expectedDef, def.addrs) { t.Errorf("Hosts which went to the default proxy didn't match. Got %v, want %v", def.addrs, expectedDef) } if !reflect.DeepEqual(expectedBypass, bypass.addrs) { t.Errorf("Hosts which went to the bypass proxy didn't match. Got %v, want %v", bypass.addrs, expectedBypass) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/proxy/proxy.go000066400000000000000000000046071264464372400233400ustar00rootroot00000000000000// 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 proxy provides support for a variety of protocols to proxy network // data. package proxy // import "golang.org/x/net/proxy" import ( "errors" "net" "net/url" "os" ) // A Dialer is a means to establish a connection. type Dialer interface { // Dial connects to the given address via the proxy. Dial(network, addr string) (c net.Conn, err error) } // Auth contains authentication parameters that specific Dialers may require. type Auth struct { User, Password string } // FromEnvironment returns the dialer specified by the proxy related variables in // the environment. func FromEnvironment() Dialer { allProxy := os.Getenv("all_proxy") if len(allProxy) == 0 { return Direct } proxyURL, err := url.Parse(allProxy) if err != nil { return Direct } proxy, err := FromURL(proxyURL, Direct) if err != nil { return Direct } noProxy := os.Getenv("no_proxy") if len(noProxy) == 0 { return proxy } perHost := NewPerHost(proxy, Direct) perHost.AddFromString(noProxy) return perHost } // proxySchemes is a map from URL schemes to a function that creates a Dialer // from a URL with such a scheme. var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error) // RegisterDialerType takes a URL scheme and a function to generate Dialers from // a URL with that scheme and a forwarding Dialer. Registered schemes are used // by FromURL. func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) { if proxySchemes == nil { proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error)) } proxySchemes[scheme] = f } // FromURL returns a Dialer given a URL specification and an underlying // Dialer for it to make network requests. func FromURL(u *url.URL, forward Dialer) (Dialer, error) { var auth *Auth if u.User != nil { auth = new(Auth) auth.User = u.User.Username() if p, ok := u.User.Password(); ok { auth.Password = p } } switch u.Scheme { case "socks5": return SOCKS5("tcp", u.Host, auth, forward) } // If the scheme doesn't match any of the built-in schemes, see if it // was registered by another package. if proxySchemes != nil { if f, ok := proxySchemes[u.Scheme]; ok { return f(u, forward) } } return nil, errors.New("proxy: unknown scheme: " + u.Scheme) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/proxy/proxy_test.go000066400000000000000000000064701264464372400243770ustar00rootroot00000000000000// 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 proxy import ( "io" "net" "net/url" "strconv" "sync" "testing" ) func TestFromURL(t *testing.T) { endSystem, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("net.Listen failed: %v", err) } defer endSystem.Close() gateway, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("net.Listen failed: %v", err) } defer gateway.Close() var wg sync.WaitGroup wg.Add(1) go socks5Gateway(t, gateway, endSystem, socks5Domain, &wg) url, err := url.Parse("socks5://user:password@" + gateway.Addr().String()) if err != nil { t.Fatalf("url.Parse failed: %v", err) } proxy, err := FromURL(url, Direct) if err != nil { t.Fatalf("FromURL failed: %v", err) } _, port, err := net.SplitHostPort(endSystem.Addr().String()) if err != nil { t.Fatalf("net.SplitHostPort failed: %v", err) } if c, err := proxy.Dial("tcp", "localhost:"+port); err != nil { t.Fatalf("FromURL.Dial failed: %v", err) } else { c.Close() } wg.Wait() } func TestSOCKS5(t *testing.T) { endSystem, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("net.Listen failed: %v", err) } defer endSystem.Close() gateway, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("net.Listen failed: %v", err) } defer gateway.Close() var wg sync.WaitGroup wg.Add(1) go socks5Gateway(t, gateway, endSystem, socks5IP4, &wg) proxy, err := SOCKS5("tcp", gateway.Addr().String(), nil, Direct) if err != nil { t.Fatalf("SOCKS5 failed: %v", err) } if c, err := proxy.Dial("tcp", endSystem.Addr().String()); err != nil { t.Fatalf("SOCKS5.Dial failed: %v", err) } else { c.Close() } wg.Wait() } func socks5Gateway(t *testing.T, gateway, endSystem net.Listener, typ byte, wg *sync.WaitGroup) { defer wg.Done() c, err := gateway.Accept() if err != nil { t.Errorf("net.Listener.Accept failed: %v", err) return } defer c.Close() b := make([]byte, 32) var n int if typ == socks5Domain { n = 4 } else { n = 3 } if _, err := io.ReadFull(c, b[:n]); err != nil { t.Errorf("io.ReadFull failed: %v", err) return } if _, err := c.Write([]byte{socks5Version, socks5AuthNone}); err != nil { t.Errorf("net.Conn.Write failed: %v", err) return } if typ == socks5Domain { n = 16 } else { n = 10 } if _, err := io.ReadFull(c, b[:n]); err != nil { t.Errorf("io.ReadFull failed: %v", err) return } if b[0] != socks5Version || b[1] != socks5Connect || b[2] != 0x00 || b[3] != typ { t.Errorf("got an unexpected packet: %#02x %#02x %#02x %#02x", b[0], b[1], b[2], b[3]) return } if typ == socks5Domain { copy(b[:5], []byte{socks5Version, 0x00, 0x00, socks5Domain, 9}) b = append(b, []byte("localhost")...) } else { copy(b[:4], []byte{socks5Version, 0x00, 0x00, socks5IP4}) } host, port, err := net.SplitHostPort(endSystem.Addr().String()) if err != nil { t.Errorf("net.SplitHostPort failed: %v", err) return } b = append(b, []byte(net.ParseIP(host).To4())...) p, err := strconv.Atoi(port) if err != nil { t.Errorf("strconv.Atoi failed: %v", err) return } b = append(b, []byte{byte(p >> 8), byte(p)}...) if _, err := c.Write(b); err != nil { t.Errorf("net.Conn.Write failed: %v", err) return } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/proxy/socks5.go000066400000000000000000000130541264464372400233620ustar00rootroot00000000000000// 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 proxy import ( "errors" "io" "net" "strconv" ) // SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address // with an optional username and password. See RFC 1928. func SOCKS5(network, addr string, auth *Auth, forward Dialer) (Dialer, error) { s := &socks5{ network: network, addr: addr, forward: forward, } if auth != nil { s.user = auth.User s.password = auth.Password } return s, nil } type socks5 struct { user, password string network, addr string forward Dialer } const socks5Version = 5 const ( socks5AuthNone = 0 socks5AuthPassword = 2 ) const socks5Connect = 1 const ( socks5IP4 = 1 socks5Domain = 3 socks5IP6 = 4 ) var socks5Errors = []string{ "", "general failure", "connection forbidden", "network unreachable", "host unreachable", "connection refused", "TTL expired", "command not supported", "address type not supported", } // Dial connects to the address addr on the network net via the SOCKS5 proxy. func (s *socks5) Dial(network, addr string) (net.Conn, error) { switch network { case "tcp", "tcp6", "tcp4": default: return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network) } conn, err := s.forward.Dial(s.network, s.addr) if err != nil { return nil, err } closeConn := &conn defer func() { if closeConn != nil { (*closeConn).Close() } }() host, portStr, err := net.SplitHostPort(addr) if err != nil { return nil, err } port, err := strconv.Atoi(portStr) if err != nil { return nil, errors.New("proxy: failed to parse port number: " + portStr) } if port < 1 || port > 0xffff { return nil, errors.New("proxy: port number out of range: " + portStr) } // the size here is just an estimate buf := make([]byte, 0, 6+len(host)) buf = append(buf, socks5Version) if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 { buf = append(buf, 2 /* num auth methods */, socks5AuthNone, socks5AuthPassword) } else { buf = append(buf, 1 /* num auth methods */, socks5AuthNone) } if _, err := conn.Write(buf); err != nil { return nil, errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error()) } if _, err := io.ReadFull(conn, buf[:2]); err != nil { return nil, errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error()) } if buf[0] != 5 { return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0]))) } if buf[1] == 0xff { return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication") } if buf[1] == socks5AuthPassword { buf = buf[:0] buf = append(buf, 1 /* password protocol version */) buf = append(buf, uint8(len(s.user))) buf = append(buf, s.user...) buf = append(buf, uint8(len(s.password))) buf = append(buf, s.password...) if _, err := conn.Write(buf); err != nil { return nil, errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) } if _, err := io.ReadFull(conn, buf[:2]); err != nil { return nil, errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) } if buf[1] != 0 { return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password") } } buf = buf[:0] buf = append(buf, socks5Version, socks5Connect, 0 /* reserved */) if ip := net.ParseIP(host); ip != nil { if ip4 := ip.To4(); ip4 != nil { buf = append(buf, socks5IP4) ip = ip4 } else { buf = append(buf, socks5IP6) } buf = append(buf, ip...) } else { if len(host) > 255 { return nil, errors.New("proxy: destination hostname too long: " + host) } buf = append(buf, socks5Domain) buf = append(buf, byte(len(host))) buf = append(buf, host...) } buf = append(buf, byte(port>>8), byte(port)) if _, err := conn.Write(buf); err != nil { return nil, errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) } if _, err := io.ReadFull(conn, buf[:4]); err != nil { return nil, errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) } failure := "unknown error" if int(buf[1]) < len(socks5Errors) { failure = socks5Errors[buf[1]] } if len(failure) > 0 { return nil, errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure) } bytesToDiscard := 0 switch buf[3] { case socks5IP4: bytesToDiscard = net.IPv4len case socks5IP6: bytesToDiscard = net.IPv6len case socks5Domain: _, err := io.ReadFull(conn, buf[:1]) if err != nil { return nil, errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error()) } bytesToDiscard = int(buf[0]) default: return nil, errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr) } if cap(buf) < bytesToDiscard { buf = make([]byte, bytesToDiscard) } else { buf = buf[:bytesToDiscard] } if _, err := io.ReadFull(conn, buf); err != nil { return nil, errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error()) } // Also need to discard the port number if _, err := io.ReadFull(conn, buf[:2]); err != nil { return nil, errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error()) } closeConn = nil return conn, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/publicsuffix/000077500000000000000000000000001264464372400231435ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/publicsuffix/gen.go000066400000000000000000000401041264464372400242420ustar00rootroot00000000000000// Copyright 2012 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. // +build ignore package main // This program generates table.go and table_test.go. // Invoke as: // // go run gen.go -version "xxx" >table.go // go run gen.go -version "xxx" -test >table_test.go // // The version is derived from information found at // https://github.com/publicsuffix/list/commits/master/public_suffix_list.dat // // To fetch a particular git revision, such as 5c70ccd250, pass // -url "https://raw.githubusercontent.com/publicsuffix/list/5c70ccd250/public_suffix_list.dat" import ( "bufio" "bytes" "flag" "fmt" "go/format" "io" "net/http" "os" "regexp" "sort" "strings" "golang.org/x/net/idna" ) const ( nodesBitsChildren = 9 nodesBitsICANN = 1 nodesBitsTextOffset = 15 nodesBitsTextLength = 6 childrenBitsWildcard = 1 childrenBitsNodeType = 2 childrenBitsHi = 14 childrenBitsLo = 14 ) var ( maxChildren int maxTextOffset int maxTextLength int maxHi uint32 maxLo uint32 ) func max(a, b int) int { if a < b { return b } return a } func u32max(a, b uint32) uint32 { if a < b { return b } return a } const ( nodeTypeNormal = 0 nodeTypeException = 1 nodeTypeParentOnly = 2 numNodeType = 3 ) func nodeTypeStr(n int) string { switch n { case nodeTypeNormal: return "+" case nodeTypeException: return "!" case nodeTypeParentOnly: return "o" } panic("unreachable") } var ( labelEncoding = map[string]uint32{} labelsList = []string{} labelsMap = map[string]bool{} rules = []string{} // validSuffix is used to check that the entries in the public suffix list // are in canonical form (after Punycode encoding). Specifically, capital // letters are not allowed. validSuffix = regexp.MustCompile(`^[a-z0-9_\!\*\-\.]+$`) crush = flag.Bool("crush", true, "make the generated node text as small as possible") subset = flag.Bool("subset", false, "generate only a subset of the full table, for debugging") url = flag.String("url", "https://publicsuffix.org/list/effective_tld_names.dat", "URL of the publicsuffix.org list. If empty, stdin is read instead") v = flag.Bool("v", false, "verbose output (to stderr)") version = flag.String("version", "", "the effective_tld_names.dat version") test = flag.Bool("test", false, "generate table_test.go") ) func main() { if err := main1(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func main1() error { flag.Parse() if nodesBitsTextLength+nodesBitsTextOffset+nodesBitsICANN+nodesBitsChildren > 32 { return fmt.Errorf("not enough bits to encode the nodes table") } if childrenBitsLo+childrenBitsHi+childrenBitsNodeType+childrenBitsWildcard > 32 { return fmt.Errorf("not enough bits to encode the children table") } if *version == "" { return fmt.Errorf("-version was not specified") } var r io.Reader = os.Stdin if *url != "" { res, err := http.Get(*url) if err != nil { return err } if res.StatusCode != http.StatusOK { return fmt.Errorf("bad GET status for %s: %d", *url, res.Status) } r = res.Body defer res.Body.Close() } var root node icann := false buf := new(bytes.Buffer) br := bufio.NewReader(r) for { s, err := br.ReadString('\n') if err != nil { if err == io.EOF { break } return err } s = strings.TrimSpace(s) if strings.Contains(s, "BEGIN ICANN DOMAINS") { icann = true continue } if strings.Contains(s, "END ICANN DOMAINS") { icann = false continue } if s == "" || strings.HasPrefix(s, "//") { continue } s, err = idna.ToASCII(s) if err != nil { return err } if !validSuffix.MatchString(s) { return fmt.Errorf("bad publicsuffix.org list data: %q", s) } if *subset { switch { case s == "ac.jp" || strings.HasSuffix(s, ".ac.jp"): case s == "ak.us" || strings.HasSuffix(s, ".ak.us"): case s == "ao" || strings.HasSuffix(s, ".ao"): case s == "ar" || strings.HasSuffix(s, ".ar"): case s == "arpa" || strings.HasSuffix(s, ".arpa"): case s == "cy" || strings.HasSuffix(s, ".cy"): case s == "dyndns.org" || strings.HasSuffix(s, ".dyndns.org"): case s == "jp": case s == "kobe.jp" || strings.HasSuffix(s, ".kobe.jp"): case s == "kyoto.jp" || strings.HasSuffix(s, ".kyoto.jp"): case s == "om" || strings.HasSuffix(s, ".om"): case s == "uk" || strings.HasSuffix(s, ".uk"): case s == "uk.com" || strings.HasSuffix(s, ".uk.com"): case s == "tw" || strings.HasSuffix(s, ".tw"): case s == "zw" || strings.HasSuffix(s, ".zw"): case s == "xn--p1ai" || strings.HasSuffix(s, ".xn--p1ai"): // xn--p1ai is Russian-Cyrillic "рф". default: continue } } rules = append(rules, s) nt, wildcard := nodeTypeNormal, false switch { case strings.HasPrefix(s, "*."): s, nt = s[2:], nodeTypeParentOnly wildcard = true case strings.HasPrefix(s, "!"): s, nt = s[1:], nodeTypeException } labels := strings.Split(s, ".") for n, i := &root, len(labels)-1; i >= 0; i-- { label := labels[i] n = n.child(label) if i == 0 { if nt != nodeTypeParentOnly && n.nodeType == nodeTypeParentOnly { n.nodeType = nt } n.icann = n.icann && icann n.wildcard = n.wildcard || wildcard } labelsMap[label] = true } } labelsList = make([]string, 0, len(labelsMap)) for label := range labelsMap { labelsList = append(labelsList, label) } sort.Strings(labelsList) p := printReal if *test { p = printTest } if err := p(buf, &root); err != nil { return err } b, err := format.Source(buf.Bytes()) if err != nil { return err } _, err = os.Stdout.Write(b) return err } func printTest(w io.Writer, n *node) error { fmt.Fprintf(w, "// generated by go run gen.go; DO NOT EDIT\n\n") fmt.Fprintf(w, "package publicsuffix\n\nvar rules = [...]string{\n") for _, rule := range rules { fmt.Fprintf(w, "%q,\n", rule) } fmt.Fprintf(w, "}\n\nvar nodeLabels = [...]string{\n") if err := n.walk(w, printNodeLabel); err != nil { return err } fmt.Fprintf(w, "}\n") return nil } func printReal(w io.Writer, n *node) error { const header = `// generated by go run gen.go; DO NOT EDIT package publicsuffix const version = %q const ( nodesBitsChildren = %d nodesBitsICANN = %d nodesBitsTextOffset = %d nodesBitsTextLength = %d childrenBitsWildcard = %d childrenBitsNodeType = %d childrenBitsHi = %d childrenBitsLo = %d ) const ( nodeTypeNormal = %d nodeTypeException = %d nodeTypeParentOnly = %d ) // numTLD is the number of top level domains. const numTLD = %d ` fmt.Fprintf(w, header, *version, nodesBitsChildren, nodesBitsICANN, nodesBitsTextOffset, nodesBitsTextLength, childrenBitsWildcard, childrenBitsNodeType, childrenBitsHi, childrenBitsLo, nodeTypeNormal, nodeTypeException, nodeTypeParentOnly, len(n.children)) text := makeText() if text == "" { return fmt.Errorf("internal error: makeText returned no text") } for _, label := range labelsList { offset, length := strings.Index(text, label), len(label) if offset < 0 { return fmt.Errorf("internal error: could not find %q in text %q", label, text) } maxTextOffset, maxTextLength = max(maxTextOffset, offset), max(maxTextLength, length) if offset >= 1<= 1< 64 { n, plus = 64, " +" } fmt.Fprintf(w, "%q%s\n", text[:n], plus) text = text[n:] } n.walk(w, assignIndexes) fmt.Fprintf(w, ` // nodes is the list of nodes. Each node is represented as a uint32, which // encodes the node's children, wildcard bit and node type (as an index into // the children array), ICANN bit and text. // // In the //-comment after each node's data, the nodes indexes of the children // are formatted as (n0x1234-n0x1256), with * denoting the wildcard bit. The // nodeType is printed as + for normal, ! for exception, and o for parent-only // nodes that have children but don't match a domain label in their own right. // An I denotes an ICANN domain. // // The layout within the uint32, from MSB to LSB, is: // [%2d bits] unused // [%2d bits] children index // [%2d bits] ICANN bit // [%2d bits] text index // [%2d bits] text length var nodes = [...]uint32{ `, 32-nodesBitsChildren-nodesBitsICANN-nodesBitsTextOffset-nodesBitsTextLength, nodesBitsChildren, nodesBitsICANN, nodesBitsTextOffset, nodesBitsTextLength) if err := n.walk(w, printNode); err != nil { return err } fmt.Fprintf(w, `} // children is the list of nodes' children, the parent's wildcard bit and the // parent's node type. If a node has no children then their children index // will be in the range [0, 6), depending on the wildcard bit and node type. // // The layout within the uint32, from MSB to LSB, is: // [%2d bits] unused // [%2d bits] wildcard bit // [%2d bits] node type // [%2d bits] high nodes index (exclusive) of children // [%2d bits] low nodes index (inclusive) of children var children=[...]uint32{ `, 32-childrenBitsWildcard-childrenBitsNodeType-childrenBitsHi-childrenBitsLo, childrenBitsWildcard, childrenBitsNodeType, childrenBitsHi, childrenBitsLo) for i, c := range childrenEncoding { s := "---------------" lo := c & (1<> childrenBitsLo) & (1<>(childrenBitsLo+childrenBitsHi)) & (1<>(childrenBitsLo+childrenBitsHi+childrenBitsNodeType) != 0 fmt.Fprintf(w, "0x%08x, // c0x%04x (%s)%s %s\n", c, i, s, wildcardStr(wildcard), nodeTypeStr(nodeType)) } fmt.Fprintf(w, "}\n\n") fmt.Fprintf(w, "// max children %d (capacity %d)\n", maxChildren, 1<= 1<= 1<= 1< 0 && ss[0] == "" { ss = ss[1:] } // Join strings where one suffix matches another prefix. for { // Find best i, j, k such that ss[i][len-k:] == ss[j][:k], // maximizing overlap length k. besti := -1 bestj := -1 bestk := 0 for i, s := range ss { if s == "" { continue } for j, t := range ss { if i == j { continue } for k := bestk + 1; k <= len(s) && k <= len(t); k++ { if s[len(s)-k:] == t[:k] { besti = i bestj = j bestk = k } } } } if bestk > 0 { if *v { fmt.Fprintf(os.Stderr, "%d-length overlap at (%4d,%4d) out of (%4d,%4d): %q and %q\n", bestk, besti, bestj, len(ss), len(ss), ss[besti], ss[bestj]) } ss[besti] += ss[bestj][bestk:] ss[bestj] = "" continue } break } text := strings.Join(ss, "") if *v { fmt.Fprintf(os.Stderr, "crushed %d bytes to become %d bytes\n", beforeLength, len(text)) } return text } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/publicsuffix/list.go000066400000000000000000000074351264464372400244560ustar00rootroot00000000000000// Copyright 2012 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 publicsuffix provides a public suffix list based on data from // http://publicsuffix.org/. A public suffix is one under which Internet users // can directly register names. package publicsuffix // import "golang.org/x/net/publicsuffix" // TODO: specify case sensitivity and leading/trailing dot behavior for // func PublicSuffix and func EffectiveTLDPlusOne. import ( "fmt" "net/http/cookiejar" "strings" ) // List implements the cookiejar.PublicSuffixList interface by calling the // PublicSuffix function. var List cookiejar.PublicSuffixList = list{} type list struct{} func (list) PublicSuffix(domain string) string { ps, _ := PublicSuffix(domain) return ps } func (list) String() string { return version } // PublicSuffix returns the public suffix of the domain using a copy of the // publicsuffix.org database compiled into the library. // // icann is whether the public suffix is managed by the Internet Corporation // for Assigned Names and Numbers. If not, the public suffix is privately // managed. For example, foo.org and foo.co.uk are ICANN domains, // foo.dyndns.org and foo.blogspot.co.uk are private domains. // // Use cases for distinguishing ICANN domains like foo.com from private // domains like foo.appspot.com can be found at // https://wiki.mozilla.org/Public_Suffix_List/Use_Cases func PublicSuffix(domain string) (publicSuffix string, icann bool) { lo, hi := uint32(0), uint32(numTLD) s, suffix, wildcard := domain, len(domain), false loop: for { dot := strings.LastIndex(s, ".") if wildcard { suffix = 1 + dot } if lo == hi { break } f := find(s[1+dot:], lo, hi) if f == notFound { break } u := nodes[f] >> (nodesBitsTextOffset + nodesBitsTextLength) icann = u&(1<>= nodesBitsICANN u = children[u&(1<>= childrenBitsLo hi = u & (1<>= childrenBitsHi switch u & (1<>= childrenBitsNodeType wildcard = u&(1<>= nodesBitsTextLength offset := x & (1< len(b[j]) } // eTLDPlusOneTestCases come from // https://github.com/publicsuffix/list/blob/master/tests/test_psl.txt var eTLDPlusOneTestCases = []struct { domain, want string }{ // Empty input. {"", ""}, // Unlisted TLD. {"example", ""}, {"example.example", "example.example"}, {"b.example.example", "example.example"}, {"a.b.example.example", "example.example"}, // TLD with only 1 rule. {"biz", ""}, {"domain.biz", "domain.biz"}, {"b.domain.biz", "domain.biz"}, {"a.b.domain.biz", "domain.biz"}, // TLD with some 2-level rules. {"com", ""}, {"example.com", "example.com"}, {"b.example.com", "example.com"}, {"a.b.example.com", "example.com"}, {"uk.com", ""}, {"example.uk.com", "example.uk.com"}, {"b.example.uk.com", "example.uk.com"}, {"a.b.example.uk.com", "example.uk.com"}, {"test.ac", "test.ac"}, // TLD with only 1 (wildcard) rule. {"mm", ""}, {"c.mm", ""}, {"b.c.mm", "b.c.mm"}, {"a.b.c.mm", "b.c.mm"}, // More complex TLD. {"jp", ""}, {"test.jp", "test.jp"}, {"www.test.jp", "test.jp"}, {"ac.jp", ""}, {"test.ac.jp", "test.ac.jp"}, {"www.test.ac.jp", "test.ac.jp"}, {"kyoto.jp", ""}, {"test.kyoto.jp", "test.kyoto.jp"}, {"ide.kyoto.jp", ""}, {"b.ide.kyoto.jp", "b.ide.kyoto.jp"}, {"a.b.ide.kyoto.jp", "b.ide.kyoto.jp"}, {"c.kobe.jp", ""}, {"b.c.kobe.jp", "b.c.kobe.jp"}, {"a.b.c.kobe.jp", "b.c.kobe.jp"}, {"city.kobe.jp", "city.kobe.jp"}, {"www.city.kobe.jp", "city.kobe.jp"}, // TLD with a wildcard rule and exceptions. {"ck", ""}, {"test.ck", ""}, {"b.test.ck", "b.test.ck"}, {"a.b.test.ck", "b.test.ck"}, {"www.ck", "www.ck"}, {"www.www.ck", "www.ck"}, // US K12. {"us", ""}, {"test.us", "test.us"}, {"www.test.us", "test.us"}, {"ak.us", ""}, {"test.ak.us", "test.ak.us"}, {"www.test.ak.us", "test.ak.us"}, {"k12.ak.us", ""}, {"test.k12.ak.us", "test.k12.ak.us"}, {"www.test.k12.ak.us", "test.k12.ak.us"}, // Punycoded IDN labels {"xn--85x722f.com.cn", "xn--85x722f.com.cn"}, {"xn--85x722f.xn--55qx5d.cn", "xn--85x722f.xn--55qx5d.cn"}, {"www.xn--85x722f.xn--55qx5d.cn", "xn--85x722f.xn--55qx5d.cn"}, {"shishi.xn--55qx5d.cn", "shishi.xn--55qx5d.cn"}, {"xn--55qx5d.cn", ""}, {"xn--85x722f.xn--fiqs8s", "xn--85x722f.xn--fiqs8s"}, {"www.xn--85x722f.xn--fiqs8s", "xn--85x722f.xn--fiqs8s"}, {"shishi.xn--fiqs8s", "shishi.xn--fiqs8s"}, {"xn--fiqs8s", ""}, } func TestEffectiveTLDPlusOne(t *testing.T) { for _, tc := range eTLDPlusOneTestCases { got, _ := EffectiveTLDPlusOne(tc.domain) if got != tc.want { t.Errorf("%q: got %q, want %q", tc.domain, got, tc.want) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/publicsuffix/table.go000066400000000000000000020322021264464372400245620ustar00rootroot00000000000000// generated by go run gen.go; DO NOT EDIT package publicsuffix const version = "publicsuffix.org's public_suffix_list.dat, git revision 1f3ad51 (2015-12-05)" const ( nodesBitsChildren = 9 nodesBitsICANN = 1 nodesBitsTextOffset = 15 nodesBitsTextLength = 6 childrenBitsWildcard = 1 childrenBitsNodeType = 2 childrenBitsHi = 14 childrenBitsLo = 14 ) const ( nodeTypeNormal = 0 nodeTypeException = 1 nodeTypeParentOnly = 2 ) // numTLD is the number of top level domains. const numTLD = 1534 // Text is the combined text of all labels. const text = "bievatmallorcafederationhsangoceanographiquebifukagawalterbihoro" + "logyusuisservicesanjotateyamabikedagestangebilbaogakievenesannan" + "ikinuyamanouchikuhokuryugasakitashiobarabillustrationikkoebenhav" + "nikolaeverbankasukabeeldengeluidunloppacificartoonartdecoffeedba" + "ckasumigaurawa-mazowszextraspace-to-rentalstomakomaibarabioddabi" + "rdartcenterprisesakikonairbusantiquest-a-la-maisondre-landebudej" + "judygarlandunsagamiharabirkenesoddtangenovaravennagatorogersvpal" + "anaklodzkodairabirthplacebjarkoyuudmurtiabjerkreimmobilienikonan" + "tanangerbjugninohelplfinancialipetskasuyakutiablockbusternidupon" + "tariomutashinainvestmentsannohelsinkitahiroshimarshallstatebanka" + "szubyuzawabloombergbauernurembergliwicebluedatinglobalashovhachi" + "noheguris-a-candidatebmoattachmentsanokatowicebmsantabarbarabmwe" + "groweiboltatsunostrowiecasadelamonedavvesiidazaifudaigodoesntexi" + "stanbullensakerbnpparibaselburglobodoes-itveronaharimalvikatsush" + "ikabeerbolzanore-og-uvdalivornostrowwlkpmglogoweirbomloansantacr" + "uzsantafedexhibitioninomiyakonojoshkar-olayangroupaleobondurbana" + "mexeterbonnirasakis-a-catererbookingloppenzaogashimadachicagoboa" + "tsanukis-a-celticsfanishiazais-a-chefarsundurhamburgminakamichig" + "angwonishigotpantheonishiharabootsaotomeldalomzansimagicaseihich" + "isobetsuitairaboschaefflerdalorenskogmodenakatombetsumidatlantic" + "asertaishinomakikuchikuseikarugapartmentsapodhalewismillerbostik" + "atsuyamasfjordenishiizunazukis-a-conservativefsncfailotenkawabos" + "tonakijinsekikogentingmxboxfinityuzhno-sakhalinskaufenishikataka" + "zakis-a-cpadoval-daostavalleybotanicalgardenishikatsuragivestbyt" + "omaritimekeepingretakamoriokamchatkameokameyamashinatsukigatakan" + "abeatsapporobotanicgardenishikawazukanazawabotanyboutiquebecngri" + "mstadvrdnsaratovalleaostavernishimerabozentsujiiebradescorporati" + "onishinomiyashironobrandywinevalleybrasiljan-mayenishinoomotegot" + "sukisosakitagatakamatsukawabresciabrindisibenikebristolgalsacebr" + "itishcolumbialowiezagannakadomari-elasticbeanstalkautokeinobroad" + "castlebtimnetzgorzeleccollegersundwgripebroadwaybroke-itattoolsz" + "tynsettlersardegnamsskoganeis-a-cubicle-slavellinowtvalled-aosta" + "vropolicebrokerrypropertiesardiniabronnoysundyndns-homednsarlott" + "ebrothermesaverdefensejnybrumunddalottokigawabrunelblagdenesnaas" + "eralingenkainanaejrietisalatinabenogatagajobojis-a-democrataxihu" + "anishinoshimatta-varjjatgorybrusselsarpsborgriwataraidyndns-ip6b" + "ruxellesarufutsunomiyawakasaikaitakoelnishiokoppegardyndns-mailo" + "uvrepbodyndns-blogdnsasayamabryanskjervoyagebryneustarhubalatino" + "rdre-landiscountysvardolls3-us-west-1buskerudinewhampshirecipesa" + "ro-urbino-pesarourbinopesaromaniwakuratelekommunikationishitosas" + "himizunaminamiashigarabuzenishiwakis-a-designerbuzzgradyndns-off" + "ice-on-the-webcambridgestonewspaperbwfashionissandoybzhitomirkut" + "skleppalermomasvuotnakatsugawacolognewmexicoldwarmiamiastaplesch" + "ulezajskfhskhabarovskhakassiacolonialwilliamsburguitarschwarzgwa" + "ngjuifminamibosogndaluxembourgujolstercoloradoplateaudiocolumbus" + "heycommunitysfjordyroyrvikingulencomobaracomparemarkerryhotelsch" + "weizippodlasiellakasamatsudoosandiegokaseljordcompute-1computerh" + "istoryofscience-fictioncomsecuritysnesciencecentersciencehistory" + "condoshichinohedmarkhangelskypescaravantaaconferenceconstruction" + "consuladoharuhrconsultanthropologyconsultingvolluxurycontactjxn-" + "-11b4c3dcontemporaryarteducationalchikugojomedicaltanissettaiwan" + "airforceocontractorskenconventureshinodesashibetsuikimobetsuligu" + "riacookingchannelveruminamidaitomangotembaixadacoolkuszjcbnluzer" + "ncoopocznorthwesternmutualvivano-frankivskharkivalledaostakkofue" + "lcopenhagencyclopedicdn77-sslattumetlifeinsurancecorsicahcesuolo" + "calhistoryazannefrankfurtkmaxxn--1ck2e1balestrandabergamoarekemb" + "roideryokozemergencyberlevagangaviikanonjibestadiscoveryggeelvin" + "ckarlsoyomitanobninskarmoyonabaruconnectargets-itargibigawasmata" + "rtanddesignieznorddalavagiske164corvettemasekharkovallee-aostero" + "ycosenzamamibuildingunmarriottmpamperedchefastlycostumedio-campi" + "dano-mediocampidanomediocouncilcouponscientistor-elvdalcoursescj" + "ohnsoncq-acranbrookuwanalyticscrapper-sitecreditcardcreditunionc" + "remonashorokanaiecrewiiheyaizuwakamatsubushikusakadogawacricketr" + "zyncrimeacrotonewportlligatewaycrowncrscrappinguovdageaidnulmina" + "miechizencruisesettsurfauskedsmokorsetagayasells-for-lessevastop" + "olecuisinellajollamericanexpressexyzlgushikamifuranotairesevenas" + "sisicilyculturalcentertainmentoyokawacuneocupcakecxn--1ctwolomin" + "amatamayukis-a-geekhersoncymruovatoyonakagyokutoshimacyouthdfcba" + "nkhmelnitskiyamashikefilminamifuranofinalfinancefineartsewildlif" + "estylefinlandfinnoyfirebaseappanasonicheltenham-radio-operaunite" + "lemarkazimierz-dolnyfirenzefirestonextdirectoryfirmdalegolfedjej" + "uegoshikiminokamoenairguardfishingonohejis-a-greenfitjarqhachioj" + "iyahikobeauxartsandcraftsfranziskanerimamateramochizukirafitness" + "ettlementoyonofjalerflickragerotikaluganskhmelnytskyivalleeaoste" + "igenflightshangrilangevagrarboretumbriaflirumansionsharis-a-guru" + "lsandvikcoromantovalle-daostavangerfloguchikuzenfloraflorenceflo" + "ridafloristanohatakaharussiafloromskogflowersharparaglidingflsmi" + "dthruhereggiocalabriaflynnhubalsanagochihayaakasakawaharaumakeup" + "owiathletajimabariakemersongdalenviknakanojohanamakinoharasnesod" + "denmarkets3-ap-southeast-2fndfolldalfoodnetworkangerfor-better-t" + "handafor-ourfor-somedizinhistorischeshawaiijimarylandfor-theater" + "forexrothachirogatakanezawaforgotdnshellaspeziaforli-cesena-forl" + "icesenaforlikes-piedmontblancomeereshimokawaforsaleikangerforsan" + "dasuolodingenfortmissoulan-udell-ogliastrakhanawawilliamhillfort" + "worthadanotogawaforuminamiiselectoyookarasjohkaminoyamatsuris-a-" + "hard-workerfosneshimokitayamafotoyosatotalfoxn--1lqs71dfreiburgf" + "reightcmwinbalsfjordishakotankarpaczeladz-2freseniusdecorativear" + "tshimonitayanagivingfribourgfriuli-v-giuliafriuli-ve-giuliafriul" + "i-vegiuliafriuli-venezia-giuliafriuli-veneziagiuliafriuli-vgiuli" + "afriuliv-giuliafriulive-giuliafriulivegiuliafriulivenezia-giulia" + "friuliveneziagiuliafriulivgiuliafrlfroganshimonosekikawafrognfro" + "landfrom-akrehamnfrom-alfrom-arfrom-azwindmillfrom-capebretonami" + "asakuchinotsuchiurakawassamukawataricohdavvenjargamvikhvanylveni" + "cefrom-collectionfrom-ctoyotaris-a-hunterfrom-dchelyabinskydivin" + "grondarfrom-dellogliastraderfrom-flandershimosuwalkis-a-knightoy" + "otomiyazakis-a-landscaperugiafrom-gaulardalfrom-higashiagatsumag" + "oirminamiizukamitondabayashiogamagoriziafrom-iafrom-idfrom-ilfro" + "m-incheonfrom-kshimotsukefrom-kyknetoyotsukaidovre-eikerfrom-lan" + "bibaidarfrom-manxn--1qqw23afrom-mdfrom-meetoyourafrom-microsoftb" + "anklabudhabikinokawabarthadselfipirangafrom-mnfrom-modalenfrom-m" + "shimotsumafrom-mtnfrom-nchernigovernmentjeldsundyndns-remotegild" + "eskalmykiafrom-ndfrom-nexusgardenfrom-nhktoystre-slidrettozawafr" + "om-njcparisor-fronfrom-nminamimakis-a-lawyerfrom-nvaolbia-tempio" + "-olbiatempioolbialystokkemerovodkagoshimaintenancefrom-nyfrom-oh" + "kurafrom-oketogurafrom-orfrom-paderbornfrom-pratohmaoris-a-liber" + "alfrom-ris-a-libertarianfrom-schoenbrunnfrom-sdnipropetrovskmpsp" + "baltimore-og-romsdalimanowarudastronomykolaivanovosibirskiptvete" + "rinairebungoonomichinomiyakepnordkappgjemnes3-eu-central-1from-t" + "nfrom-txn--2m4a15efrom-utazuerichardlikescandyndns-at-homedepota" + "ruis-a-linux-useranishiaritabashikaoizumizakitaurayasudafrom-vad" + "sochildrensgardenfrom-vtozsdefrom-wafrom-wielunnerfrom-wvareserv" + "eftparliamentranbyfrom-wyfrosinonefrostalowa-wolawafroyahabadajo" + "zorahkkeravjuedischesapeakebayerndfstcgrouparmafujiiderafujikawa" + "guchikonefujiminohtawaramotoineppugliafujinomiyadafujiokayamarbu" + "rgfujisatoshonairlinebraskaunbieidsvollfujisawafujishiroishidaka" + "biratoridelmenhorstalbanshinichinanfujitsurugashimarinefujixerox" + "n--30rr7yfujiyoshidafukayabeardubaiduckdnsdojoburgfukuchiyamadaf" + "ukudominichernihivgucciprianiigataitoeiheijis-a-doctorayfukuis-a" + "-llamarylhursteinkjerusalembetsukuis-a-musicianfukumitsubishigak" + "irkeneshinjournalismailillehammerfest-mon-blogueurovisionfukuoka" + "zakirovogradoyfukuroishikarikaturindalfukusakiryuohaebaruminamim" + "inowafukuyamagatakahashimamakisarazure-mobileirfjordfunabashiriu" + "chinadafunagatakahatakaishimoichinosekigaharafunahashikamiamakus" + "atsumasendaisennangoodyearthagakhanamigawafundaciofuoiskujukuriy" + "amarcheaparocherkasyzrankoshigayaltaikis-a-nascarfanfuosskoczowi" + "ndowshinjukumanofurnitureggioemiliaromagnakasatsunairportland-4-" + "salernogiessengerdalaskanittedallasalleaseeklogesurancefurubiraq" + "uarelleasingleshinkamigotoyohashimotomobeneventochiokinoshimalse" + "lvendrellfurudonostiafurukawairtelecityeatshinshinotsurgeonshall" + "offamelhustkamisunagawafusodegaurafussaikishiwadafutabayamaguchi" + "nomigawafutboldlygoingnowhere-for-moregontrailroadfuttsurugimina" + "miogunicomcastresistancefvgfyis-a-nurseoullensvanguardfylkesbibl" + "ackfridayfyresdalhanyuzenhapmirhappoulvikokonoehareidsbergenhars" + "tadharvestcelebrationhasamarahasaminami-alpssells-for-unzenhashb" + "anghasudahasvikolobrzegyptianpachigasakidstvedestrandhatogayahoo" + "oshikamaishimofusartshinyoshitomiokaniepcehatoyamazakitahatakaok" + "amikitayamatotakadahatsukaichiharahattfjelldalhayashimamotobungo" + "takadatsunanjoetsuwanouchikujogaszkoladbrokesennumamurogawarszaw" + "ashingtondclkomaganehazuminobusells-itraniandriabarlettatraniand" + "riahboehringerikehembygdsforbundhemneshiojirishirifujiedahemseda" + "lherokussldheroyhgtvaroyhigashichichibunkyonanaoshimageandsounda" + "ndvisionhigashihiroshimanehigashiizumozakitakamiizumisanofiatran" + "oyhigashikagawahigashikagurasoedahigashikawakitaaikitakatakarazu" + "kamikoaniikappulawyhigashikurumeguroroskoleitungsenhigashimatsus" + "himarugame-hostinghigashimatsuyamakitaakitadaitoigawahigashimura" + "yamalatvuopmidoris-a-personaltrainerhigashinarusellsyourhomegood" + "shioyameloyalistockholmestrandhigashinehigashiomihachimanchester" + "higashiosakasayamamotorcycleshirahamatonbetsurgeryhigashishiraka" + "wamatakasagooglecodespotransportrapaniimimatakatoris-a-photograp" + "herokuappartis-a-playerhigashisumiyoshikawaminamiaikitakyushuaia" + "higashitsunowruzhgorodoyhigashiurausukitamidsundhigashiyamatokor" + "iyamanakakogawahigashiyodogawahigashiyoshinogaris-a-republicance" + "rresearchaeologicaliforniahiraizumisatohnoshoohirakatashinagawah" + "iranairtraffichernovtsykkylvenetogakushimotoganewjerseyhirarahir" + "atsukagawahirayaitakasakitamotosumitakaginankokubunjis-a-rocksta" + "rachowicehisayamanashiibaghdadultravelchannelhistorichouseshirak" + "oenighitachiomiyaginowaniihamatamakawajimaritimodellinghitachiot" + "agopartnershiranukanmakiwakunigamihamadahitoyoshimifunehitrading" + "hjartdalhjelmelandholeckobierzyceholidayhomeipartshiraois-a-soci" + "alistmeindianapolis-a-bloggerhomelinuxn--32vp30hagebostadhomesen" + "sembokukitanakagusukumoduminamisanrikubetsupplyhomeunixn--3bst00" + "minamitanehondahonefosshiraokannamiharuhoneywellhongorgehonjyoit" + "akashimarumorimachidahornindalhorseminehortendofinternetravelers" + "insurancehoteleshiratakahagis-a-soxfanhotmailhoyangerhoylandetro" + "itskomakiyosatokamachippubetsubetsugaruhumanitieshishikuis-a-stu" + "dentalhurdalhurumajis-a-teacherkassymantechnologyhyllestadhyogor" + "is-a-techietis-a-therapistoiahyugawarahyundaiwafunejgorajlchitac" + "hinakagawatchandclockazojlljmpartyjnjelenia-gorajoyokaichibahcav" + "uotnagaraholtalenjpmorganichitosetogitsuldalucaniajpnchloejprshi" + "zuokanoyakagejuniperjurkristiansandcatshoujis-an-entertainerkris" + "tiansundkrodsheradkrokstadelvaldaostarostwodzislawinnershowakrym" + "inamiuonumatsumaebashimodatekumatorinokumejimasudakumenanyokkaic" + "hirurgiens-dentisteshowtimemerckommunekunisakis-bykunitachiarail" + "waykunitomigusukumamotoyamassa-carrara-massacarraramassabusiness" + "ebykleclerchocolatelevisionissayokoshibahikariwanumataketomisato" + "kuyamatteledatabaseballooningrongausdaluccapetownissedalucerneku" + "nneppupasadenamsosnowiechofunatorientexpressatxjaworznokunstsamm" + "lungkunstunddesignkuokgroupassagenshriramsterdambulancekurepair-" + "traffic-controlleykurgankurobelgorodeokurogimilitarykuroisoftwar" + "endalenugkuromatsunais-certifiedekakegawakurotakikawasakis-found" + "ationkurskomonokushirogawakustanais-gonekusupersportrentino-stir" + "olkutchanelkutnokuzbassnillfjordkuzumakis-into-animeiwamaseratis" + "-an-accountantshisognekvafjordkvalsundkvamlidlugolekagaminord-au" + "rdalvdalipayufuchukotkafjordkvanangenkvinesdalkvinnheradkvitesei" + "dskogkvitsoykwpspjelkavikomorotsukamishihoronobeokaminokawanishi" + "aizubangekyotobetsuppliesienarashinokyowariasahikawamissilelmisu" + "gitokonamegatakayamatsunomitakeharamitourismolanciamitoyoakemiur" + "amiyazurewebsiteshikagamiishibukawamiyotamanomjondalenmlbarcelon" + "agasakijobservercellierneues3-us-west-2monmouthaibarakitagawamon" + "stermonticellolmontrealestatefarmequipmentrentino-sud-tirolmonza" + "-brianzaporizhzhekinannestadmonza-e-della-brianzaporizhzhiamonza" + "brianzapposlombardiamondsimbirskongsbergmonzaebrianzaramonzaedel" + "labrianzamoparachutingmordoviajessheiminamiyamashirokawanabellev" + "uelosangelesjaguarchitecturealtychyattorneyagawalbrzycharternopi" + "lawalesundmoriyamatsusakahoginozawaonsenmoriyoshiokamitsuemormon" + "eymoroyamatsushigemortgagemoscowiostrolekaneyamaxunjargamoseushi" + "storymosjoenmoskenesimple-urlmossirdalmosvikongsvingermoviemovis" + "targardmtpccwitdkoninjamisonmtranakayamatsuuramuenstermugithubus" + "ercontentrentino-sudtirolmuikamogawamukochikushinonsenergymulhou" + "servebbslingmultichoicemunakatanemuncieszynmuosattemupassenger-a" + "ssociationmurmanskonskowolancashireisenmurotorcraftrentino-sued-" + "tirolmusashimurayamatsuzakis-leetrdmusashinoharamuseetrentino-su" + "edtirolmuseumverenigingmutsuzawamutuellevangermypetslupskonsulat" + "robelaudiblebesbyglandmyphotoshibahccavuotnagareyamaizurubtsovsk" + "jakdnepropetrovskiervaapsteiermarkonyveloftrentino-altoadigemyti" + "s-a-bookkeeperminanophiladelphiaareadmyblogsitephilatelyphilipsy" + "phoenixn--3e0b707ephotographysiopiagetmyipaviancapitalonewhollan" + "dpictetrentinoa-adigepicturesnzpiemontepilotsokanrapinkopervikom" + "itamamurapioneerpippupiszpittsburghofermobilypiwatepizzapkoryola" + "siteplanetariumincommbankomvuxn--3ds443gplantationplantsokndalpl" + "atforminnesotaketakatsukis-into-carshitaramaplaystationplazaplch" + "onanbuildersaudaplombardyndns-at-workinggroupfizerplumbingotvbar" + "claycardsakuraibmdiskstationaustdalimitedunetflixilimoliserniauk" + "raanghkebinagisoccertificationaturalhistorymuseumcenterhcloudcon" + "trolledds3-external-1plusterpmnpodzonepohlpokerpokrovskosaigawap" + "olitiendapolkowicepoltavalle-aostathellexuslivinghistorypomorzes" + "zowithgoogleapisa-hockeynutrentinoaadigepordenonepornporsangerpo" + "rsangugeporsgrunnanpoznanpraxis-a-bruinsfansolarssonprdpreservat" + "ionpresidioprimelbourneprincipeprivneprochowiceproductionsologne" + "proferraraprogressivenneslaskerrylogisticsolundbeckosakaerodrome" + "gallupinbananarepublicarrierprojectrentinoalto-adigepromombetsup" + "portrentinoaltoadigepropertyprotectionprudentialpruszkowithyoutu" + "bentleyprzeworskogptzpvtrentinos-tirolpwchoseiroumuenchenisshing" + "uernseypzqldqponqslgbtrentinostirolqvchoshibuyachiyodastpetersbu" + "rgstudiostudyndns-freemasonryokamikawanehonbetsurutaharastuff-4-" + "salestuttgartrentinosued-tirolsurnadalsurreysusakis-slickomatsus" + "himashikiyosemitesusonosuzakanumazurysuzukanzakiwiensuzukis-uber" + "leetrentino-a-adigesvalbardudinkakamigaharasveiosvelvikosherbroo" + "kegawasvizzeraswedenswidnicarbonia-iglesias-carboniaiglesiascarb" + "oniaswiebodzindianmarketingswiftcoverisignswinoujscienceandhisto" + "ryswisshikis-very-badaddjamalborkdalsxn--3oq18vl8pn36atunesootur" + "ystykarasjoksnesopotrentinosud-tiroltuscanytushuissier-justicetu" + "valle-d-aostatoilvestnesor-varangervestre-slidreamhostersorfoldv" + "estre-totennishiawakuravestvagoyvevelstadvibo-valentiavibovalent" + "iavideovillaskoyabearalvahkihokumakogeniwaizumiotsukumiyamazonaw" + "sabaerobaticketsaritsynologyeongbukoshunantokashikizunokunimilan" + "ovinnicargodaddynathomebuiltrentottoris-very-evillagevinnytsiavi" + "psinaappharmaciensmolenskooris-an-actresshisuifuettertdasnetzvir" + "giniavirtualvirtuelvisakatakinouevistaprintuitrevisohughesolutio" + "nsomaviterboknowsitallvivoldavladikavkazanvladimirvladivostokaiz" + "ukarasuyamazoevlogvolgogradvolkenkunderseaportroandinosaureportr" + "entinosuedtirolvolkswagentsorreisahayakawakamiichikaiseis-savedu" + "catorahimeshimakanegasakinkobayashikshacknetnedalvologdanskostro" + "mahachijorpelandvolyngdalvoronezhytomyrvossevangenvotevotingvoto" + "ursortlandvrnworse-thangglidingwowiwatsukiyonowritesthisblogspot" + "rogstadwroclawloclawekosugewtchoyodobashichikashukujitawarawtfer" + "rarittogoldpointelligencewuozuwwworldwzmiuwajimaxn--4gbriminingx" + "n--4gq48lf9jeonnamerikawauexn--4it168dxn--4it797kotouraxn--4pvxs" + "oruminternationalfirearmsigdalxn--54b7fta0cchryslerxn--55qw42gxn" + "--55qx5dxn--5js045dxn--5rtp49chtrainingrossetouchijiwadeltajimic" + "rolightingroundhandlingroznyxn--5rtq34kouhokutamakis-an-artistjo" + "hnxn--5su34j936bgsgxn--5tzm5gxn--6btw5axn--6frz82gxn--6orx2rxn--" + "6qq986b3xlxn--7t0a264chungbukazunoxn--80adxhksouthcarolinazawaxn" + "--80ao21axn--80aqecdr1axn--80asehdbarclaysakyotanabellunordreisa" + "-geekarumaifarmsteadivtasvuodnakaiwamizawaurskog-holandroverhall" + "a-speziaetnagahamaroygardenebakkeshibechambagricaaarborteaches-y" + "ogasawaracingroks-theatree12xn--80aswgxn--80audnedalnxn--8ltr62k" + "ounosunndalxn--8pvr4uxn--8y0a063axn--90a3academydscloudappspoten" + "zachpomorskiendoftheinternetcimdbarefootballangenoamishirasatobi" + "shimalopolskanlandivttasvuotnakamagayachtsalangenaval-d-aosta-va" + "lleyonagoyaustevollavangenaturalsciencesnaturelles3-external-2xn" + "--90aishobaraomoriguchiharagusaarlandxn--90azhakatanotteroyxn--9" + "dbhblg6diethnologyxn--9dbq2axn--9et52uxn--9krt00axn--andy-iraxn-" + "-aroport-byanagawaxn--asky-iraxn--aurskog-hland-jnbargainstitute" + "lefonicagliaridagawallonieruchomoscienceandindustrynavigationavu" + "otnakhodkanagawaustinnaturbruksgymnaturhistorisches3-fips-us-gov" + "-west-1xn--avery-yuasakegawaxn--b-5gaxn--b4w605ferdxn--bck1b9a5d" + "re4chungnamdalseidfjordyndns-weberlincolniyodogawaxn--bdddj-mrab" + "dxn--bearalvhki-y4axn--berlevg-jxaxn--bhcavuotna-s4axn--bhccavuo" + "tna-k7axn--bidr-5nachikatsuuraxn--bievt-0qa2xn--bjarky-fyanaizux" + "n--bjddar-ptamboversaillesor-odalxn--blt-elaborxn--bmlo-grainger" + "xn--bod-2naroyxn--brnny-wuaccident-investigationjukudoyamacerata" + "buseat-band-campaniamallamadridvagsoyericssonlineat-urlxn--brnny" + "sund-m8accident-preventionxn--brum-voagatromsakakinokiaxn--btsfj" + "ord-9zaxn--c1avgxn--c2br7gxn--c3s14misakis-into-cartoonshizukuis" + "himogosenxn--cck2b3barreauctionayoroceanographicsalondonetskasao" + "kamiokamiminersaltdalindasiaustraliaisondriodejaneirochesterxn--" + "cg4bkis-very-goodhandsonxn--ciqpnxn--clchc0ea0b2g2a9gcdn77-secur" + "ecreationxn--comunicaes-v6a2oxn--correios-e-telecomunicaes-ghc29" + "axn--czr694barrel-of-knowledgeologyonaguniversityoriikashibataka" + "sugaiinetarnobrzegjovikashiharaustrheimatunduhrennesoyekaterinbu" + "rgjerdrumckinseyokosukareliancebinosegawagrinetbankz-1kappleanga" + "viikadenaamesjevuemielnoboribetsucks3-ap-northeast-1xn--czrs0tro" + "msojavald-aostarnbergxn--czru2dxn--czrw28barrell-of-knowledgeome" + "tre-experts-comptablesalvadordalibabaikaliszczytnordlandiyukuhas" + "himojiitatebayashijonawatextileksvikashiwarauthordalandroidgcame" + "rakershus-east-1xn--d1acj3bashkiriautomotivecodyn-o-saurlandes3-" + "sa-east-1xn--d1alfaromeoxn--d1atrusteexn--d5qv7z876churchaseljee" + "pilepsydneyxn--davvenjrga-y4axn--djrs72d6uyxn--djty4kouyamashiko" + "kuchuoxn--dnna-grajewolterskluwerxn--drbak-wuaxn--dyry-iraxn--ec" + "kvdtc9dxn--efvn9southwestfalenxn--efvy88hakodatevaksdalxn--ehqz5" + "6nxn--elqq16hakonexn--estv75gxn--eveni-0qa01gaxn--f6qx53axn--fct" + "429kouzushimasoyxn--fhbeiarnxn--finny-yuaxn--fiq228c5hsowaxn--fi" + "q64basilicataniautoscanadaejeonbukariyakumoldebizenakaniikawatan" + "aguragroks-thisamitsukeisenbahnativeamericanantiques3-ap-southea" + "st-1xn--fiqs8spreadbettingxn--fiqz9spydebergxn--fjord-lraxn--fjq" + "720axn--fl-ziaxn--flor-jraxn--flw351exn--fpcrj9c3dxn--frde-grand" + "rapidsrlxn--frna-woaraisaijosoyrovigorlicexn--frya-hraxn--fzc2c9" + "e2chuvashiaxn--fzys8d69uvgmailxn--g2xx48circlegallocuscountryest" + "ateofdelawaredumbrellahppiacenzakopaneraircraftraeumtgeradealsta" + "haugesundyndns-wikindlegnicampobassociatesavannahgaxn--gckr3f0fe" + "rreroticanonoichikawamisatodayxn--gecrj9circuscultureggio-calabr" + "iaxn--ggaviika-8ya47hakubankmshinshiroxn--gildeskl-g0axn--givuot" + "na-8yandexn--3pxu8kotohiradomainsureitrentino-s-tirollagricultur" + "ennebudapest-a-la-masionxn--gjvik-wuaxn--gk3at1exn--gls-elacaixa" + "xn--gmq050is-very-nicexn--gmqw5axn--h-2fairwindsrtrentinosudtiro" + "lxn--h1aeghakuis-a-painteractivegarsheis-a-patsfanxn--h2brj9cita" + "deliverybnikahokutogliattiresaves-the-whalessandria-trani-barlet" + "ta-andriatranibarlettaandriaxn--hbmer-xqaxn--hcesuolo-7ya35baske" + "tballfinanzgoraveroykenvironmentalconservationatuurwetenschappen" + "aumburgjerstadotsuruokamakurazakisofukushimarnardalaziobirakuned" + "re-eikereviewskrakowebhopagefrontappagespeedmobilizerobihirosaki" + "kamijimaeroportalabamagasakishimabarackmaze-burggfarmerseinewyor" + "kshireggio-emilia-romagnakanotoddenasushiobarabruzzoologicalvink" + "lein-addrammenuernbergdyniabogadocscbg12000xn--hery-iraxn--hgebo" + "stad-g3axn--hmmrfeasta-s4acoachampionshiphopenair-surveillancebe" + "tsukubabia-goracleaningatlantachikawakayamagadancechirealtorland" + "xn--hnefoss-q1axn--hobl-iraxn--holtlen-hxaxn--hpmir-xqaxn--hxt81" + "4exn--hyanger-q1axn--hylandet-54axn--i1b6b1a6a2exn--imr513nxn--i" + "ndery-fyaotsurgutsiracusaitokyotangovtrverranzanxn--io0a7is-very" + "-sweetrentino-aadigexn--j1aefetsundxn--j1amhakusandnessjoenxn--j" + "6w193gxn--jlq61u9w7batochigiftsalzburgladeloittenrightathomeftpa" + "ccessamegawavocatanzaroweddingjesdalillesandefjordigitalillyokot" + "ehimeji234xn--jlster-byaroslavlaanderenxn--jrpeland-54axn--jvr18" + "9misasaguris-into-gamessinashikitchenxn--k7yn95exn--karmy-yuaxn-" + "-kbrq7oxn--kcrx77d1x4axn--kfjord-iuaxn--klbu-woaxn--klt787dxn--k" + "ltp7dxn--kltx9axn--klty5xn--42c2d9axn--koluokta-7ya57haldenxn--k" + "prw13dxn--kpry57dxn--kpu716fgxn--1lqs03nxn--kput3is-with-theband" + "oomdnsaliascolipicenord-odalxn--krager-gyasakaiminatoyakokamisat" + "ohobby-sitexasdaburyatiaarpharmacysnoasaitamatsukuris-lostre-tot" + "eneis-an-actorxn--kranghke-b0axn--krdsherad-m8axn--krehamn-dxaxn" + "--krjohka-hwab49jetztrentino-alto-adigexn--ksnes-uuaxn--kvfjord-" + "nxaxn--kvitsy-fyasugisleofmandalxn--kvnangen-k0axn--l-1faithegua" + "rdianquanconagawakuyabukicks-assediciticateringebugattipschmidtr" + "e-gauldalovegaskimitsubatamicadaquesaskatchewanggouvicenzaxn--l1" + "accentureklamborghiniizaxn--laheadju-7yasuokaratexn--langevg-jxa" + "xn--lcvr32dxn--ldingen-q1axn--leagaviika-52batsfjordnpalacemrxn-" + "-lesund-huaxn--lgbbat1ad8jevnakerxn--lgrd-poacivilaviationrwhali" + "ngrpalmspringsakerxn--lhppi-xqaxn--linds-pramericanartrysilkoshi" + "mizumakiyosumyokohamamatsudaxn--lns-qlanxessrvdonskoseis-an-anar" + "chistoricalsocietyxn--loabt-0qaxn--lrdal-sraxn--lrenskog-54axn--" + "lt-liacivilisationxn--lten-granexn--lury-iraxn--mely-iraxn--merk" + "er-kuaxn--mgb2ddestoragexn--mgb9awbfidelityumenxn--mgba3a3ejtula" + "nsomnaritakurashikis-not-certifiedogawarabikomaezakirunoshiroomu" + "raxn--mgba3a4f16axn--mgba3a4franamizuholdingsmileirvikozagawaxn-" + "-mgba7c0bbn0axn--mgbaakc7dvfidonnakamuratakahamannortonsbergzpan" + "amaxn--mgbaam7a8halsaintlouis-a-anarchistoirehabmerxn--mgbab2bdx" + "n--mgbai9a5eva00bauhausposts-and-telecommunicationsnasadodgeorge" + "orgiavoues3-us-gov-west-1xn--mgbai9azgqp6jewelryxn--mgbayh7gpadu" + "axn--mgbb9fbpobanazawaxn--mgbbh1a71exn--mgbc0a9azcgxn--mgbca7dzd" + "ownloadxn--mgberp4a5d4a87gxn--mgberp4a5d4arxn--mgbi4ecexposedxn-" + "-mgbpl2fhvalerxn--mgbqly7c0a67fbcivilizationxn--mgbqly7cvafredri" + "kstadtvstordalxn--mgbt3dhdxn--mgbtf8flekkefjordxn--mgbtx2bbcarti" + "erxn--mgbx4cd0abbvieeexn--mix082fieldxn--mix891figuerestaurantoy" + "onezawaxn--mjndalen-64axn--mk0axindustriesteamfamberkeleyxn--mk1" + "bu44civilwarmanagementjmaxxxn--0trq7p7nnxn--mkru45issmarterthany" + "ouxn--mlatvuopmi-s4axn--mli-tlapyatigorskozakis-an-engineeringxn" + "--mlselv-iuaxn--moreke-juaxn--mori-qsakuhokkaidontexisteingeekpn" + "xn--mosjen-eyatominamiawajikiwchiryukyuragifuefukihaborokunoheal" + "thcareersassaris-a-financialadvisor-aurdalowiczest-le-patrondhei" + "mperiaxn--mot-tlaquilancasterxn--mre-og-romsdal-qqbbtarumizusawa" + "xamusementarantomsk-uralsk12xn--msy-ula0hammarfeastafricamagiche" + "rnivtsiciliaxn--mtta-vrjjat-k7afamilycompanyclaimsavonaplesaxoxn" + "--muost-0qaxn--mxtq1misawaxn--ngbc5azdxn--ngbe9e0axn--nit225kpps" + "piegelxn--nmesjevuemie-tcbajddarchaeologyxn--nnx388axn--nodessak" + "uragawaxn--nqv7fs00emaxn--nry-yla5gxn--ntso0iqx3axn--ntsq17gxn--" + "nttery-byaeservegame-serverdalxn--nvuotna-hwaxn--nyqy26axn--o1ac" + "hattanooganorilskodjeffersonxn--o3cw4hamurakamigoriginshintokush" + "imaxn--od0algxn--od0aq3bbvacationswatch-and-clockerxn--ogbpf8fle" + "sbergxn--oppegrd-ixaxn--ostery-fyatsukaratsuginamikatagamihobole" + "slawieclickchristiansburgruexn--osyro-wuaxn--p1acfdxn--p1aixn--p" + "bt977clinicatholicasinorfolkebiblefrakkestadyndns-picsasebofagex" + "n--pgbs0dhlxn--porsgu-sta26filateliaxn--pssu33lxn--pssy2uxn--q9j" + "yb4cliniquenoharaxn--qcka1pmcdonaldstorenburgxn--qqqt11misconfus" + "edxn--qxamurskinderoyxn--rady-iraxn--rdal-poaxn--rde-ularvikrasn" + "odarxn--rdy-0nabarixn--rennesy-v1axn--rhkkervju-01aflakstadaokag" + "akibichuoxn--rholt-mragowoodsidexn--rhqv96gxn--rht27zxn--rht3dxn" + "--rht61exn--risa-5narusawaxn--risr-iraxn--rland-uuaxn--rlingen-m" + "xaxn--rmskog-byatsushiroxn--rny31hangoutsystemscloudcontrolappar" + "shintomikasaharaxn--rovu88beppubolognagasukepostfoldnavyatkakuda" + "matsuepsonyoursidegreevje-og-hornnesamnangerxn--rros-granvindafj" + "ordxn--rskog-uuaxn--rst-0narutokorozawaxn--rsta-francaiseharaxn-" + "-ryken-vuaxn--ryrvik-byawaraxn--s-1fareastcoastaldefencexn--s9br" + "j9clintonoshoesbschokoladenxn--sandnessjen-ogbizhevskrasnoyarsko" + "mmunalforbundxn--sandy-yuaxn--seral-lraxn--ses554gxn--sgne-grata" + "ngenxn--skierv-utazaskvolloabathsbclothinguideventscholarshipsch" + "oolukowhoswhokksundyndns-workshoppdaluroyxn--skjervy-v1axn--skjk" + "-soaxn--sknit-yqaxn--sknland-fxaxn--slat-5narviikananporovnoxn--" + "slt-elabourxn--smla-hraxn--smna-gratis-a-bulls-fanxn--snase-nrax" + "n--sndre-land-0cbremangerxn--snes-poaxn--snsa-roaxn--sr-aurdal-l" + "8axn--sr-fron-q1axn--sr-odal-q1axn--sr-varanger-ggbernrtatamotor" + "samsclubindalindesnesamsunglassassinationalheritagematsubarakawa" + "goexn--srfold-byawatahamaxn--srreisa-q1axn--srum-grazxn--stfold-" + "9xaxn--stjrdal-s1axn--stjrdalshalsen-sqbeskidynaliascoli-picenor" + "d-frontierxn--stre-toten-zcbstorfjordxn--t60b56axn--tckweatherch" + "annelxn--tiq49xqyjewishartgalleryxn--tjme-hraxn--tn0agrigentomol" + "ogyeonggiehtavuoatnagaivuotnagaokakyotambabydgoszczecinemailxn--" + "tnsberg-q1axn--tor131oxn--trany-yuaxn--trgstad-r1axn--trna-woaxn" + "--troms-zuaxn--tysvr-vraxn--uc0atversicherungxn--uc0ay4axn--uist" + "22hannanmokuizumodernxn--uisz3gxn--unjrga-rtaobaokinawashirosato" + "bamagazinemurorangemologicallyngenglandxn--unup4yxn--uuwu58axn--" + "vads-jraxn--vard-jraxn--vegrshei-c0axn--vermgensberater-ctbestbu" + "yshousesanfranciscotlandrangedalinkashiwazakiyokawaraxn--vermgen" + "sberatung-pwbetainaboxfordeatnuorockartuzyurihonjournalistjordal" + "shalsenflatangerxn--vestvgy-ixa6oxn--vg-yiabcgxn--vgan-qoaxn--vg" + "sy-qoa0jfkomforbambleborkaruizawaugustowadaegubs3-eu-west-1xn--v" + "gu402cloudfrontdoorxn--vhquvestfoldxn--vler-qoaxn--vre-eiker-k8a" + "xn--vrggt-xqadxn--vry-yla5gxn--vuq861bhartiffanynysafetydalinzai" + "iyamanobedzin-the-bandaioirasebastopologyusuharaxn--w4r85el8fhu5" + "dnraxn--w4rs40lxn--wcvs22dxn--wgbh1cntjomemorialutskddielddanuor" + "rikuzentakatajirissagaeroclubmedecincinnationwidealerimo-i-ranad" + "exchangeiseiyoichiropracticbcn-north-1xn--wgbl6axn--xhq521bielaw" + "almartatarstanfshostrodawaraxn--xkc2al3hye2axn--xkc2dl3a5ee0hann" + "ovarggatrani-andria-barletta-trani-andriaxn--y9a3aquariumishimat" + "sumotofukexn--yer-znarvikredstonexn--yfro4i67oxn--ygarden-p1axn-" + "-ygbi2ammxn--45brj9christmasakikugawatchesauheradyndns-serverban" + "iaxn--ystre-slidre-ujbiellaakesvuemieleccexn--zbx025dxn--zf0ao64" + "axn--zf0avxn--45q11chromediaxn--zfr164bieszczadygeyachimataipeig" + "ersundrivelandrobaknoluoktainaibetsubamericanfamilydsmynaspersch" + "lesischesquarezzoologyeongnamegawakembuchikumagayagawakkanaikawa" + "chinaganoharamcoalaheadjudaicabbottateshinanomachintaijinfinitin" + "foggiaxperiaxz" // nodes is the list of nodes. Each node is represented as a uint32, which // encodes the node's children, wildcard bit and node type (as an index into // the children array), ICANN bit and text. // // In the //-comment after each node's data, the nodes indexes of the children // are formatted as (n0x1234-n0x1256), with * denoting the wildcard bit. The // nodeType is printed as + for normal, ! for exception, and o for parent-only // nodes that have children but don't match a domain label in their own right. // An I denotes an ICANN domain. // // The layout within the uint32, from MSB to LSB, is: // [ 1 bits] unused // [ 9 bits] children index // [ 1 bits] ICANN bit // [15 bits] text index // [ 6 bits] text length var nodes = [...]uint32{ 0x002ffc03, // n0x0000 c0x0000 (---------------) + I aaa 0x003495c4, // n0x0001 c0x0000 (---------------) + I aarp 0x002634c6, // n0x0002 c0x0000 (---------------) + I abarth 0x00361383, // n0x0003 c0x0000 (---------------) + I abb 0x003a4746, // n0x0004 c0x0000 (---------------) + I abbott 0x00361386, // n0x0005 c0x0000 (---------------) + I abbvie 0x00394a83, // n0x0006 c0x0000 (---------------) + I abc 0x0031c444, // n0x0007 c0x0000 (---------------) + I able 0x0033a687, // n0x0008 c0x0000 (---------------) + I abogado 0x00263108, // n0x0009 c0x0000 (---------------) + I abudhabi 0x01a03982, // n0x000a c0x0006 (n0x05fe-n0x0604) + I ac 0x00301a47, // n0x000b c0x0000 (---------------) + I academy 0x0034f009, // n0x000c c0x0000 (---------------) + I accenture 0x002b610a, // n0x000d c0x0000 (---------------) + I accountant 0x002b610b, // n0x000e c0x0000 (---------------) + I accountants 0x0022a743, // n0x000f c0x0000 (---------------) + I aco 0x00332686, // n0x0010 c0x0000 (---------------) + I active 0x00233385, // n0x0011 c0x0000 (---------------) + I actor 0x01e0c682, // n0x0012 c0x0007 (n0x0604-n0x0605) + I ad 0x00210cc4, // n0x0013 c0x0000 (---------------) + I adac 0x00263643, // n0x0014 c0x0000 (---------------) + I ads 0x0029b705, // n0x0015 c0x0000 (---------------) + I adult 0x02203142, // n0x0016 c0x0008 (n0x0605-n0x060d) + I ae 0x003321c3, // n0x0017 c0x0000 (---------------) + I aeg 0x026dbdc4, // n0x0018 c0x0009 (n0x060d-n0x0664) + I aero 0x002ff1c5, // n0x0019 c0x0000 (---------------) + I aetna 0x02a00342, // n0x001a c0x000a (n0x0664-n0x0669) + I af 0x0036a78e, // n0x001b c0x0000 (---------------) + I afamilycompany 0x0024a983, // n0x001c c0x0000 (---------------) + I afl 0x00369cc6, // n0x001d c0x0000 (---------------) + I africa 0x00369ccb, // n0x001e c0x0000 (---------------) + I africamagic 0x02e00c42, // n0x001f c0x000b (n0x0669-n0x066e) + I ag 0x0027b707, // n0x0020 c0x0000 (---------------) + I agakhan 0x002361c6, // n0x0021 c0x0000 (---------------) + I agency 0x03204c82, // n0x0022 c0x000c (n0x066e-n0x0672) + I ai 0x0020ccc3, // n0x0023 c0x0000 (---------------) + I aig 0x0020ccc4, // n0x0024 c0x0000 (---------------) + I aigo 0x002055c6, // n0x0025 c0x0000 (---------------) + I airbus 0x00233008, // n0x0026 c0x0000 (---------------) + I airforce 0x00280706, // n0x0027 c0x0000 (---------------) + I airtel 0x002cc044, // n0x0028 c0x0000 (---------------) + I akdn 0x036001c2, // n0x0029 c0x000d (n0x0672-n0x0679) + I al 0x0031f3c9, // n0x002a c0x0000 (---------------) + I alfaromeo 0x0031c787, // n0x002b c0x0000 (---------------) + I alibaba 0x002b7186, // n0x002c c0x0000 (---------------) + I alipay 0x00335089, // n0x002d c0x0000 (---------------) + I allfinanz 0x00209cc8, // n0x002e c0x0000 (---------------) + I allstate 0x00390684, // n0x002f c0x0000 (---------------) + I ally 0x0021ce06, // n0x0030 c0x0000 (---------------) + I alsace 0x00204a06, // n0x0031 c0x0000 (---------------) + I alstom 0x03a01682, // n0x0032 c0x000e (n0x0679-n0x067a) + I am 0x0024144f, // n0x0033 c0x0000 (---------------) + I americanexpress 0x003a294e, // n0x0034 c0x0000 (---------------) + I americanfamily 0x0020ffc4, // n0x0035 c0x0000 (---------------) + I amex 0x00362b05, // n0x0036 c0x0000 (---------------) + I amfam 0x0034e645, // n0x0037 c0x0000 (---------------) + I amica 0x002b19c9, // n0x0038 c0x0000 (---------------) + I amsterdam 0x0023d549, // n0x0039 c0x0000 (---------------) + I analytics 0x0031dd07, // n0x003a c0x0000 (---------------) + I android 0x0034d0c6, // n0x003b c0x0000 (---------------) + I anquan 0x002486c3, // n0x003c c0x0000 (---------------) + I anz 0x03e01bc2, // n0x003d c0x000f (n0x067a-n0x0680) + I ao 0x00266cc3, // n0x003e c0x0000 (---------------) + I aol 0x002147ca, // n0x003f c0x0000 (---------------) + I apartments 0x00219183, // n0x0040 c0x0000 (---------------) + I app 0x00319dc5, // n0x0041 c0x0000 (---------------) + I apple 0x0027ef82, // n0x0042 c0x0000 (---------------) + I aq 0x0027ef89, // n0x0043 c0x0000 (---------------) + I aquarelle 0x04202942, // n0x0044 c0x0010 (n0x0680-n0x0689) + I ar 0x003a4286, // n0x0045 c0x0000 (---------------) + I aramco 0x002c1405, // n0x0046 c0x0000 (---------------) + I archi 0x00344d44, // n0x0047 c0x0000 (---------------) + I army 0x04a4cb84, // n0x0048 c0x0012 (n0x068a-n0x0690) + I arpa 0x00232504, // n0x0049 c0x0000 (---------------) + I arte 0x04e02642, // n0x004a c0x0013 (n0x0690-n0x0691) + I as 0x00349304, // n0x004b c0x0000 (---------------) + I asda 0x00314604, // n0x004c c0x0000 (---------------) + I asia 0x0032c80a, // n0x004d c0x0000 (---------------) + I associates 0x05200102, // n0x004e c0x0014 (n0x0691-n0x0698) + I at 0x0024e0c7, // n0x004f c0x0000 (---------------) + I athleta 0x002c18c8, // n0x0050 c0x0000 (---------------) + I attorney 0x05a04202, // n0x0051 c0x0016 (n0x0699-n0x06ab) + I au 0x00313607, // n0x0052 c0x0000 (---------------) + I auction 0x0022ccc4, // n0x0053 c0x0000 (---------------) + I audi 0x002cb147, // n0x0054 c0x0000 (---------------) + I audible 0x0022ccc5, // n0x0055 c0x0000 (---------------) + I audio 0x0035b507, // n0x0056 c0x0000 (---------------) + I auspost 0x0031dac6, // n0x0057 c0x0000 (---------------) + I author 0x0021dc84, // n0x0058 c0x0000 (---------------) + I auto 0x003253c5, // n0x0059 c0x0000 (---------------) + I autos 0x002cea87, // n0x005a c0x0000 (---------------) + I avianca 0x06a00cc2, // n0x005b c0x001a (n0x06b9-n0x06ba) + I aw 0x002eaf83, // n0x005c c0x0000 (---------------) + I aws 0x00222ec2, // n0x005d c0x0000 (---------------) + I ax 0x00368fc3, // n0x005e c0x0000 (---------------) + I axa 0x06e04402, // n0x005f c0x001b (n0x06ba-n0x06c6) + I az 0x00279845, // n0x0060 c0x0000 (---------------) + I azure 0x07201b82, // n0x0061 c0x001c (n0x06c6-n0x06d1) + I ba 0x0038ca04, // n0x0062 c0x0000 (---------------) + I baby 0x00274805, // n0x0063 c0x0000 (---------------) + I baidu 0x0020ff07, // n0x0064 c0x0000 (---------------) + I banamex 0x002dc20e, // n0x0065 c0x0000 (---------------) + I bananarepublic 0x003101c4, // n0x0066 c0x0000 (---------------) + I band 0x00203284, // n0x0067 c0x0000 (---------------) + I bank 0x00202903, // n0x0068 c0x0000 (---------------) + I bar 0x002bbe09, // n0x0069 c0x0000 (---------------) + I barcelona 0x002d3f4b, // n0x006a c0x0000 (---------------) + I barclaycard 0x002fd888, // n0x006b c0x0000 (---------------) + I barclays 0x00302808, // n0x006c c0x0000 (---------------) + I barefoot 0x00307c88, // n0x006d c0x0000 (---------------) + I bargains 0x002af3c8, // n0x006e c0x0000 (---------------) + I baseball 0x00334eca, // n0x006f c0x0000 (---------------) + I basketball 0x0035b407, // n0x0070 c0x0000 (---------------) + I bauhaus 0x002706c6, // n0x0071 c0x0000 (---------------) + I bayern 0x076c7142, // n0x0072 c0x001d (n0x06d1-n0x06db) + I bb 0x00360e43, // n0x0073 c0x0000 (---------------) + I bbc 0x00368c83, // n0x0074 c0x0000 (---------------) + I bbt 0x003705c4, // n0x0075 c0x0000 (---------------) + I bbva 0x00394ac3, // n0x0076 c0x0000 (---------------) + I bcg 0x0039b6c3, // n0x0077 c0x0000 (---------------) + I bcn 0x0170bd82, // n0x0078 c0x0005 (---------------)* o I bd 0x07a02e82, // n0x0079 c0x001e (n0x06db-n0x06dd) + I be 0x00219045, // n0x007a c0x0000 (---------------) + I beats 0x0020e0c4, // n0x007b c0x0000 (---------------) + I beer 0x002de007, // n0x007c c0x0000 (---------------) + I bentley 0x0030b7c6, // n0x007d c0x0000 (---------------) + I berlin 0x00238a84, // n0x007e c0x0000 (---------------) + I best 0x00391e87, // n0x007f c0x0000 (---------------) + I bestbuy 0x002130c3, // n0x0080 c0x0000 (---------------) + I bet 0x07f56882, // n0x0081 c0x001f (n0x06dd-n0x06de) + I bf 0x082fb3c2, // n0x0082 c0x0020 (n0x06de-n0x0703) + I bg 0x08706042, // n0x0083 c0x0021 (n0x0703-n0x0708) + I bh 0x00397946, // n0x0084 c0x0000 (---------------) + I bharti 0x08a00002, // n0x0085 c0x0022 (n0x0708-n0x070d) + I bi 0x00373745, // n0x0086 c0x0000 (---------------) + I bible 0x0030d2c3, // n0x0087 c0x0000 (---------------) + I bid 0x00201744, // n0x0088 c0x0000 (---------------) + I bike 0x002d3d84, // n0x0089 c0x0000 (---------------) + I bing 0x002d3d85, // n0x008a c0x0000 (---------------) + I bingo 0x00204e03, // n0x008b c0x0000 (---------------) + I bio 0x08f25b83, // n0x008c c0x0023 (n0x070d-n0x0715) + I biz 0x09207642, // n0x008d c0x0024 (n0x0715-n0x0719) + I bj 0x00283f85, // n0x008e c0x0000 (---------------) + I black 0x00283f8b, // n0x008f c0x0000 (---------------) + I blackfriday 0x00252606, // n0x0090 c0x0000 (---------------) + I blanco 0x00208b8b, // n0x0091 c0x0000 (---------------) + I blockbuster 0x00225384, // n0x0092 c0x0000 (---------------) + I blog 0x0020a289, // n0x0093 c0x0000 (---------------) + I bloomberg 0x0020a9c4, // n0x0094 c0x0000 (---------------) + I blue 0x0960b542, // n0x0095 c0x0025 (n0x0719-n0x071e) + I bm 0x0020bb83, // n0x0096 c0x0000 (---------------) + I bms 0x0020bf03, // n0x0097 c0x0000 (---------------) + I bmw 0x0160d3c2, // n0x0098 c0x0005 (---------------)* o I bn 0x00234e43, // n0x0099 c0x0000 (---------------) + I bnl 0x0020d3ca, // n0x009a c0x0000 (---------------) + I bnpparibas 0x09a0c182, // n0x009b c0x0026 (n0x071e-n0x0727) + I bo 0x00210f45, // n0x009c c0x0000 (---------------) + I boats 0x0028b10a, // n0x009d c0x0000 (---------------) + I boehringer 0x00373e44, // n0x009e c0x0000 (---------------) + I bofa 0x0020ec83, // n0x009f c0x0000 (---------------) + I bom 0x0020fd84, // n0x00a0 c0x0000 (---------------) + I bond 0x00210743, // n0x00a1 c0x0000 (---------------) + I boo 0x00210744, // n0x00a2 c0x0000 (---------------) + I book 0x00210747, // n0x00a3 c0x0000 (---------------) + I booking 0x00212745, // n0x00a4 c0x0000 (---------------) + I boots 0x00213385, // n0x00a5 c0x0000 (---------------) + I bosch 0x00214e86, // n0x00a6 c0x0000 (---------------) + I bostik 0x00217743, // n0x00a7 c0x0000 (---------------) + I bot 0x00219c48, // n0x00a8 c0x0000 (---------------) + I boutique 0x09e1ac42, // n0x00a9 c0x0027 (n0x0727-n0x076d) + I br 0x0021ac48, // n0x00aa c0x0000 (---------------) + I bradesco 0x0022944b, // n0x00ab c0x0000 (---------------) + I bridgestone 0x0021ea08, // n0x00ac c0x0000 (---------------) + I broadway 0x00220246, // n0x00ad c0x0000 (---------------) + I broker 0x00221047, // n0x00ae c0x0000 (---------------) + I brother 0x00223708, // n0x00af c0x0000 (---------------) + I brussels 0x0a6a0ec2, // n0x00b0 c0x0029 (n0x076e-n0x0773) + I bs 0x0aa1e182, // n0x00b1 c0x002a (n0x0773-n0x0778) + I bt 0x00330108, // n0x00b2 c0x0000 (---------------) + I budapest 0x0034dc07, // n0x00b3 c0x0000 (---------------) + I bugatti 0x0023b305, // n0x00b4 c0x0000 (---------------) + I build 0x002d3108, // n0x00b5 c0x0000 (---------------) + I builders 0x002ade08, // n0x00b6 c0x0000 (---------------) + I business 0x002dfac3, // n0x00b7 c0x0000 (---------------) + I buy 0x00228bc4, // n0x00b8 c0x0000 (---------------) + I buzz 0x00361402, // n0x00b9 c0x0000 (---------------) + I bv 0x0ae298c2, // n0x00ba c0x002b (n0x0778-n0x077a) + I bw 0x0b20a0c2, // n0x00bb c0x002c (n0x077a-n0x077e) + I by 0x0ba29d02, // n0x00bc c0x002e (n0x077f-n0x0785) + I bz 0x00229d03, // n0x00bd c0x0000 (---------------) + I bzh 0x0be00302, // n0x00be c0x002f (n0x0785-n0x0796) + I ca 0x003a4703, // n0x00bf c0x0000 (---------------) + I cab 0x00200304, // n0x00c0 c0x0000 (---------------) + I cafe 0x002178c3, // n0x00c1 c0x0000 (---------------) + I cal 0x00390644, // n0x00c2 c0x0000 (---------------) + I call 0x00339e4b, // n0x00c3 c0x0000 (---------------) + I calvinklein 0x0031df06, // n0x00c4 c0x0000 (---------------) + I camera 0x0023bec4, // n0x00c5 c0x0000 (---------------) + I camp 0x00297ece, // n0x00c6 c0x0000 (---------------) + I cancerresearch 0x0032d1c5, // n0x00c7 c0x0000 (---------------) + I canon 0x002afa48, // n0x00c8 c0x0000 (---------------) + I capetown 0x002cebc7, // n0x00c9 c0x0000 (---------------) + I capital 0x002cebca, // n0x00ca c0x0000 (---------------) + I capitalone 0x00203ac3, // n0x00cb c0x0000 (---------------) + I car 0x00230807, // n0x00cc c0x0000 (---------------) + I caravan 0x002d4105, // n0x00cd c0x0000 (---------------) + I cards 0x00367084, // n0x00ce c0x0000 (---------------) + I care 0x00367086, // n0x00cf c0x0000 (---------------) + I career 0x00367087, // n0x00d0 c0x0000 (---------------) + I careers 0x002d2804, // n0x00d1 c0x0000 (---------------) + I cars 0x00360ec7, // n0x00d2 c0x0000 (---------------) + I cartier 0x0020c5c4, // n0x00d3 c0x0000 (---------------) + I casa 0x00212dc4, // n0x00d4 c0x0000 (---------------) + I case 0x00212dc6, // n0x00d5 c0x0000 (---------------) + I caseih 0x002c8704, // n0x00d6 c0x0000 (---------------) + I cash 0x00373446, // n0x00d7 c0x0000 (---------------) + I casino 0x00210583, // n0x00d8 c0x0000 (---------------) + I cat 0x0034d9c8, // n0x00d9 c0x0000 (---------------) + I catering 0x00373288, // n0x00da c0x0000 (---------------) + I catholic 0x00243f43, // n0x00db c0x0000 (---------------) + I cba 0x00234e03, // n0x00dc c0x0000 (---------------) + I cbn 0x003853c4, // n0x00dd c0x0000 (---------------) + I cbre 0x0038a683, // n0x00de c0x0000 (---------------) + I cbs 0x0c21e542, // n0x00df c0x0030 (n0x0796-n0x079a) + I cc 0x0c636502, // n0x00e0 c0x0031 (n0x079a-n0x079b) + I cd 0x002075c3, // n0x00e1 c0x0000 (---------------) + I ceb 0x00205146, // n0x00e2 c0x0000 (---------------) + I center 0x00233183, // n0x00e3 c0x0000 (---------------) + I ceo 0x002afe44, // n0x00e4 c0x0000 (---------------) + I cern 0x0ca15c02, // n0x00e5 c0x0032 (n0x079b-n0x079c) + I cf 0x00215c03, // n0x00e6 c0x0000 (---------------) + I cfa 0x00372c03, // n0x00e7 c0x0000 (---------------) + I cfd 0x00219482, // n0x00e8 c0x0000 (---------------) + I cg 0x0ce02302, // n0x00e9 c0x0033 (n0x079c-n0x079d) + I ch 0x002b5146, // n0x00ea c0x0000 (---------------) + I chanel 0x00234287, // n0x00eb c0x0000 (---------------) + I channel 0x0031fdc5, // n0x00ec c0x0000 (---------------) + I chase 0x00218784, // n0x00ed c0x0000 (---------------) + I chat 0x0027c105, // n0x00ee c0x0000 (---------------) + I cheap 0x003a4bc7, // n0x00ef c0x0000 (---------------) + I chintai 0x002a8d45, // n0x00f0 c0x0000 (---------------) + I chloe 0x0039f4c9, // n0x00f1 c0x0000 (---------------) + I christmas 0x003a14c6, // n0x00f2 c0x0000 (---------------) + I chrome 0x002f8ac8, // n0x00f3 c0x0000 (---------------) + I chrysler 0x0031fcc6, // n0x00f4 c0x0000 (---------------) + I church 0x0d2039c2, // n0x00f5 c0x0034 (n0x079d-n0x07ac) + I ci 0x00275548, // n0x00f6 c0x0000 (---------------) + I cipriani 0x0032aa06, // n0x00f7 c0x0000 (---------------) + I circle 0x00392385, // n0x00f8 c0x0000 (---------------) + I cisco 0x00332f07, // n0x00f9 c0x0000 (---------------) + I citadel 0x0034d8c4, // n0x00fa c0x0000 (---------------) + I citi 0x0034d8c5, // n0x00fb c0x0000 (---------------) + I citic 0x002808c4, // n0x00fc c0x0000 (---------------) + I city 0x002808c8, // n0x00fd c0x0000 (---------------) + I cityeats 0x0d604002, // n0x00fe c0x0035 (n0x07ac-n0x07ad)* o I ck 0x0da1f902, // n0x00ff c0x0036 (n0x07ad-n0x07b2) + I cl 0x0036ab06, // n0x0100 c0x0000 (---------------) + I claims 0x0033c3c8, // n0x0101 c0x0000 (---------------) + I cleaning 0x00372185, // n0x0102 c0x0000 (---------------) + I click 0x00373146, // n0x0103 c0x0000 (---------------) + I clinic 0x003750c8, // n0x0104 c0x0000 (---------------) + I clinique 0x00381888, // n0x0105 c0x0000 (---------------) + I clothing 0x002d5e05, // n0x0106 c0x0000 (---------------) + I cloud 0x00387104, // n0x0107 c0x0000 (---------------) + I club 0x0039a647, // n0x0108 c0x0000 (---------------) + I clubmed 0x0de56182, // n0x0109 c0x0037 (n0x07b2-n0x07b6) + I cm 0x0e219ec2, // n0x010a c0x0038 (n0x07b6-n0x07e3) + I cn 0x0fa03dc2, // n0x010b c0x003e (n0x07e8-n0x07f5) + I co 0x0033b685, // n0x010c c0x0000 (---------------) + I coach 0x00294405, // n0x010d c0x0000 (---------------) + I codes 0x00203dc6, // n0x010e c0x0000 (---------------) + I coffee 0x0021e587, // n0x010f c0x0000 (---------------) + I college 0x0022a787, // n0x0110 c0x0000 (---------------) + I cologne 0x1022d0c3, // n0x0111 c0x0040 (n0x07f6-n0x08c6) + I com 0x002831c7, // n0x0112 c0x0000 (---------------) + I comcast 0x002d1448, // n0x0113 c0x0000 (---------------) + I commbank 0x0022d0c9, // n0x0114 c0x0000 (---------------) + I community 0x0036a947, // n0x0115 c0x0000 (---------------) + I company 0x0022da47, // n0x0116 c0x0000 (---------------) + I compare 0x0022edc8, // n0x0117 c0x0000 (---------------) + I computer 0x0022f5c6, // n0x0118 c0x0000 (---------------) + I comsec 0x00230006, // n0x0119 c0x0000 (---------------) + I condos 0x00230d0c, // n0x011a c0x0000 (---------------) + I construction 0x0023188a, // n0x011b c0x0000 (---------------) + I consulting 0x00231d47, // n0x011c c0x0000 (---------------) + I contact 0x0023324b, // n0x011d c0x0000 (---------------) + I contractors 0x002340c7, // n0x011e c0x0000 (---------------) + I cooking 0x002340ce, // n0x011f c0x0000 (---------------) + I cookingchannel 0x00234bc4, // n0x0120 c0x0000 (---------------) + I cool 0x00235044, // n0x0121 c0x0000 (---------------) + I coop 0x00236c47, // n0x0122 c0x0000 (---------------) + I corsica 0x0032ad87, // n0x0123 c0x0000 (---------------) + I country 0x0023c7c6, // n0x0124 c0x0000 (---------------) + I coupon 0x0023c7c7, // n0x0125 c0x0000 (---------------) + I coupons 0x0023cdc7, // n0x0126 c0x0000 (---------------) + I courses 0x1160ef82, // n0x0127 c0x0045 (n0x08e4-n0x08eb) + I cr 0x0023da86, // n0x0128 c0x0000 (---------------) + I credit 0x0023da8a, // n0x0129 c0x0000 (---------------) + I creditcard 0x0023dd0b, // n0x012a c0x0000 (---------------) + I creditunion 0x0023ee07, // n0x012b c0x0000 (---------------) + I cricket 0x0023f7c5, // n0x012c c0x0000 (---------------) + I crown 0x0023f903, // n0x012d c0x0000 (---------------) + I crs 0x00240247, // n0x012e c0x0000 (---------------) + I cruises 0x0023d703, // n0x012f c0x0000 (---------------) + I csc 0x11a1f802, // n0x0130 c0x0046 (n0x08eb-n0x08f1) + I cu 0x002410ca, // n0x0131 c0x0000 (---------------) + I cuisinella 0x11f50142, // n0x0132 c0x0047 (n0x08f1-n0x08f2) + I cv 0x122c52c2, // n0x0133 c0x0048 (n0x08f2-n0x08f6) + I cw 0x12642c42, // n0x0134 c0x0049 (n0x08f6-n0x08f8) + I cx 0x12a362c2, // n0x0135 c0x004a (n0x08f8-n0x0905) o I cy 0x00243645, // n0x0136 c0x0000 (---------------) + I cymru 0x00243d44, // n0x0137 c0x0000 (---------------) + I cyou 0x13235182, // n0x0138 c0x004c (n0x0906-n0x0907) + I cz 0x00349385, // n0x0139 c0x0000 (---------------) + I dabur 0x0029b6c3, // n0x013a c0x0000 (---------------) + I dad 0x0033cb45, // n0x013b c0x0000 (---------------) + I dance 0x0020b444, // n0x013c c0x0000 (---------------) + I date 0x0020aac6, // n0x013d c0x0000 (---------------) + I dating 0x00289106, // n0x013e c0x0000 (---------------) + I datsun 0x00284183, // n0x013f c0x0000 (---------------) + I day 0x0028a244, // n0x0140 c0x0000 (---------------) + I dclk 0x002d6183, // n0x0141 c0x0000 (---------------) + I dds 0x13600402, // n0x0142 c0x004d (n0x0907-n0x090f) + I de 0x0032be44, // n0x0143 c0x0000 (---------------) + I deal 0x0039abc6, // n0x0144 c0x0000 (---------------) + I dealer 0x0032be45, // n0x0145 c0x0000 (---------------) + I deals 0x0037c406, // n0x0146 c0x0000 (---------------) + I degree 0x00333008, // n0x0147 c0x0000 (---------------) + I delivery 0x00253704, // n0x0148 c0x0000 (---------------) + I dell 0x00341a08, // n0x0149 c0x0000 (---------------) + I deloitte 0x002f9d85, // n0x014a c0x0000 (---------------) + I delta 0x00222cc8, // n0x014b c0x0000 (---------------) + I democrat 0x002a5006, // n0x014c c0x0000 (---------------) + I dental 0x002ac2c7, // n0x014d c0x0000 (---------------) + I dentist 0x002289c4, // n0x014e c0x0000 (---------------) + I desi 0x002289c6, // n0x014f c0x0000 (---------------) + I design 0x00381b03, // n0x0150 c0x0000 (---------------) + I dev 0x00374203, // n0x0151 c0x0000 (---------------) + I dhl 0x002bf448, // n0x0152 c0x0000 (---------------) + I diamonds 0x003061c4, // n0x0153 c0x0000 (---------------) + I diet 0x00342c47, // n0x0154 c0x0000 (---------------) + I digital 0x00246986, // n0x0155 c0x0000 (---------------) + I direct 0x00246989, // n0x0156 c0x0000 (---------------) + I directory 0x00226208, // n0x0157 c0x0000 (---------------) + I discount 0x00238bc8, // n0x0158 c0x0000 (---------------) + I discover 0x002564c4, // n0x0159 c0x0000 (---------------) + I dish 0x0031cdc3, // n0x015a c0x0000 (---------------) + I diy 0x00246f02, // n0x015b c0x0000 (---------------) + I dj 0x13a677c2, // n0x015c c0x004e (n0x090f-n0x0910) + I dk 0x13e07882, // n0x015d c0x004f (n0x0910-n0x0915) + I dm 0x00350cc3, // n0x015e c0x0000 (---------------) + I dnp 0x1420cdc2, // n0x015f c0x0050 (n0x0915-n0x091f) + I do 0x0033a7c4, // n0x0160 c0x0000 (---------------) + I docs 0x0035bdc5, // n0x0161 c0x0000 (---------------) + I dodge 0x0023ec83, // n0x0162 c0x0000 (---------------) + I dog 0x002311c4, // n0x0163 c0x0000 (---------------) + I doha 0x0032f687, // n0x0164 c0x0000 (---------------) + I domains 0x0022e686, // n0x0165 c0x0000 (---------------) + I doosan 0x00336343, // n0x0166 c0x0000 (---------------) + I dot 0x0035dfc8, // n0x0167 c0x0000 (---------------) + I download 0x003a2145, // n0x0168 c0x0000 (---------------) + I drive 0x00286a04, // n0x0169 c0x0000 (---------------) + I dstv 0x00360103, // n0x016a c0x0000 (---------------) + I dtv 0x00274785, // n0x016b c0x0000 (---------------) + I dubai 0x002748c4, // n0x016c c0x0000 (---------------) + I duck 0x002037c6, // n0x016d c0x0000 (---------------) + I dunlop 0x00206284, // n0x016e c0x0000 (---------------) + I duns 0x00208ec6, // n0x016f c0x0000 (---------------) + I dupont 0x0020fe46, // n0x0170 c0x0000 (---------------) + I durban 0x00310784, // n0x0171 c0x0000 (---------------) + I dvag 0x0021e843, // n0x0172 c0x0000 (---------------) + I dwg 0x14607182, // n0x0173 c0x0051 (n0x091f-n0x0927) + I dz 0x0027b5c5, // n0x0174 c0x0000 (---------------) + I earth 0x00219083, // n0x0175 c0x0000 (---------------) + I eat 0x14a03d82, // n0x0176 c0x0052 (n0x0927-n0x0933) + I ec 0x002b3785, // n0x0177 c0x0000 (---------------) + I edeka 0x002325c3, // n0x0178 c0x0000 (---------------) + I edu 0x002325c9, // n0x0179 c0x0000 (---------------) + I education 0x14e03502, // n0x017a c0x0053 (n0x0933-n0x093d) + I ee 0x1560b0c2, // n0x017b c0x0055 (n0x093e-n0x0947) + I eg 0x0038cdc5, // n0x017c c0x0000 (---------------) + I email 0x002ac686, // n0x017d c0x0000 (---------------) + I emerck 0x0024e507, // n0x017e c0x0000 (---------------) + I emerson 0x002c6d06, // n0x017f c0x0000 (---------------) + I energy 0x00364cc8, // n0x0180 c0x0000 (---------------) + I engineer 0x00364ccb, // n0x0181 c0x0000 (---------------) + I engineering 0x0020518b, // n0x0182 c0x0000 (---------------) + I enterprises 0x0037bac5, // n0x0183 c0x0000 (---------------) + I epost 0x0037c145, // n0x0184 c0x0000 (---------------) + I epson 0x002bd849, // n0x0185 c0x0000 (---------------) + I equipment 0x01600442, // n0x0186 c0x0005 (---------------)* o I er 0x00310948, // n0x0187 c0x0000 (---------------) + I ericsson 0x00208dc4, // n0x0188 c0x0000 (---------------) + I erni 0x15e013c2, // n0x0189 c0x0057 (n0x0948-n0x094d) + I es 0x003a31c3, // n0x018a c0x0000 (---------------) + I esq 0x002bd5c6, // n0x018b c0x0000 (---------------) + I estate 0x0027ebc8, // n0x018c c0x0000 (---------------) + I esurance 0x16608802, // n0x018d c0x0059 (n0x094e-n0x0956) + I et 0x00222508, // n0x018e c0x0000 (---------------) + I etisalat 0x00225c02, // n0x018f c0x0000 (---------------) + I eu 0x00277bca, // n0x0190 c0x0000 (---------------) + I eurovision 0x00225c03, // n0x0191 c0x0000 (---------------) + I eus 0x00381b46, // n0x0192 c0x0000 (---------------) + I events 0x00203188, // n0x0193 c0x0000 (---------------) + I everbank 0x0039b008, // n0x0194 c0x0000 (---------------) + I exchange 0x0031c106, // n0x0195 c0x0000 (---------------) + I expert 0x0035ed87, // n0x0196 c0x0000 (---------------) + I exposed 0x00241647, // n0x0197 c0x0000 (---------------) + I express 0x0020458a, // n0x0198 c0x0000 (---------------) + I extraspace 0x00373ec4, // n0x0199 c0x0000 (---------------) + I fage 0x00215c44, // n0x019a c0x0000 (---------------) + I fail 0x003319c9, // n0x019b c0x0000 (---------------) + I fairwinds 0x0034cdc5, // n0x019c c0x0000 (---------------) + I faith 0x0036a7c6, // n0x019d c0x0000 (---------------) + I family 0x00211483, // n0x019e c0x0000 (---------------) + I fan 0x002d9a04, // n0x019f c0x0000 (---------------) + I fans 0x002bd744, // n0x01a0 c0x0000 (---------------) + I farm 0x00338c47, // n0x01a1 c0x0000 (---------------) + I farmers 0x00229947, // n0x01a2 c0x0000 (---------------) + I fashion 0x0023ba84, // n0x01a3 c0x0000 (---------------) + I fast 0x0020f1c5, // n0x01a4 c0x0000 (---------------) + I fedex 0x00203e88, // n0x01a5 c0x0000 (---------------) + I feedback 0x002f5f47, // n0x01a6 c0x0000 (---------------) + I ferrari 0x0032cf87, // n0x01a7 c0x0000 (---------------) + I ferrero 0x16a03a42, // n0x01a8 c0x005a (n0x0956-n0x0959) + I fi 0x0028de44, // n0x01a9 c0x0000 (---------------) + I fiat 0x003568c8, // n0x01aa c0x0000 (---------------) + I fidelity 0x003596c4, // n0x01ab c0x0000 (---------------) + I fido 0x00244544, // n0x01ac c0x0000 (---------------) + I film 0x00244905, // n0x01ad c0x0000 (---------------) + I final 0x00244a47, // n0x01ae c0x0000 (---------------) + I finance 0x00208549, // n0x01af c0x0000 (---------------) + I financial 0x002454c4, // n0x01b0 c0x0000 (---------------) + I fire 0x002466c9, // n0x01b1 c0x0000 (---------------) + I firestone 0x00246bc8, // n0x01b2 c0x0000 (---------------) + I firmdale 0x002476c4, // n0x01b3 c0x0000 (---------------) + I fish 0x002476c7, // n0x01b4 c0x0000 (---------------) + I fishing 0x00247c83, // n0x01b5 c0x0000 (---------------) + I fit 0x00248e47, // n0x01b6 c0x0000 (---------------) + I fitness 0x01615242, // n0x01b7 c0x0005 (---------------)* o I fj 0x01795202, // n0x01b8 c0x0005 (---------------)* o I fk 0x00249506, // n0x01b9 c0x0000 (---------------) + I flickr 0x0024a107, // n0x01ba c0x0000 (---------------) + I flights 0x0024a9c4, // n0x01bb c0x0000 (---------------) + I flir 0x0024c107, // n0x01bc c0x0000 (---------------) + I florist 0x0024c987, // n0x01bd c0x0000 (---------------) + I flowers 0x0024cec8, // n0x01be c0x0000 (---------------) + I flsmidth 0x0024d543, // n0x01bf c0x0000 (---------------) + I fly 0x0022c142, // n0x01c0 c0x0000 (---------------) + I fm 0x002330c2, // n0x01c1 c0x0000 (---------------) + I fo 0x0024f903, // n0x01c2 c0x0000 (---------------) + I foo 0x0024f90b, // n0x01c3 c0x0000 (---------------) + I foodnetwork 0x00302908, // n0x01c4 c0x0000 (---------------) + I football 0x00393584, // n0x01c5 c0x0000 (---------------) + I ford 0x00251005, // n0x01c6 c0x0000 (---------------) + I forex 0x00252b07, // n0x01c7 c0x0000 (---------------) + I forsale 0x00254405, // n0x01c8 c0x0000 (---------------) + I forum 0x002b3eca, // n0x01c9 c0x0000 (---------------) + I foundation 0x00255a83, // n0x01ca c0x0000 (---------------) + I fox 0x16e35842, // n0x01cb c0x005b (n0x0959-n0x0971) + I fr 0x00256ac9, // n0x01cc c0x0000 (---------------) + I fresenius 0x0025a803, // n0x01cd c0x0000 (---------------) + I frl 0x0025a8c7, // n0x01ce c0x0000 (---------------) + I frogans 0x00396289, // n0x01cf c0x0000 (---------------) + I frontdoor 0x0038a088, // n0x01d0 c0x0000 (---------------) + I frontier 0x002c8c43, // n0x01d1 c0x0000 (---------------) + I ftr 0x002738c7, // n0x01d2 c0x0000 (---------------) + I fujitsu 0x00273dc9, // n0x01d3 c0x0000 (---------------) + I fujixerox 0x0027ba84, // n0x01d4 c0x0000 (---------------) + I fund 0x0027d409, // n0x01d5 c0x0000 (---------------) + I furniture 0x00282206, // n0x01d6 c0x0000 (---------------) + I futbol 0x002836c3, // n0x01d7 c0x0000 (---------------) + I fyi 0x00200c82, // n0x01d8 c0x0000 (---------------) + I ga 0x0021cdc3, // n0x01d9 c0x0000 (---------------) + I gal 0x0038b687, // n0x01da c0x0000 (---------------) + I gallery 0x0032ab85, // n0x01db c0x0000 (---------------) + I gallo 0x002dc006, // n0x01dc c0x0000 (---------------) + I gallup 0x00290184, // n0x01dd c0x0000 (---------------) + I game 0x00344485, // n0x01de c0x0000 (---------------) + I games 0x00214783, // n0x01df c0x0000 (---------------) + I gap 0x00217986, // n0x01e0 c0x0000 (---------------) + I garden 0x0020a482, // n0x01e1 c0x0000 (---------------) + I gb 0x0037fb04, // n0x01e2 c0x0000 (---------------) + I gbiz 0x00221d82, // n0x01e3 c0x0000 (---------------) + I gd 0x00225443, // n0x01e4 c0x0000 (---------------) + I gdn 0x172018c2, // n0x01e5 c0x005c (n0x0971-n0x0978) + I ge 0x0023fd03, // n0x01e6 c0x0000 (---------------) + I gea 0x002163c4, // n0x01e7 c0x0000 (---------------) + I gent 0x002163c7, // n0x01e8 c0x0000 (---------------) + I genting 0x0035be86, // n0x01e9 c0x0000 (---------------) + I george 0x0024c942, // n0x01ea c0x0000 (---------------) + I gf 0x17638e02, // n0x01eb c0x005d (n0x0978-n0x097b) + I gg 0x00238e04, // n0x01ec c0x0000 (---------------) + I ggee 0x17a4a1c2, // n0x01ed c0x005e (n0x097b-n0x0980) + I gh 0x17e12d42, // n0x01ee c0x005f (n0x0980-n0x0986) + I gi 0x00341684, // n0x01ef c0x0000 (---------------) + I gift 0x00341685, // n0x01f0 c0x0000 (---------------) + I gifts 0x00217dc5, // n0x01f1 c0x0000 (---------------) + I gives 0x00257386, // n0x01f2 c0x0000 (---------------) + I giving 0x1820a802, // n0x01f3 c0x0060 (n0x0986-n0x098b) + I gl 0x00341945, // n0x01f4 c0x0000 (---------------) + I glade 0x00387685, // n0x01f5 c0x0000 (---------------) + I glass 0x0027f2c3, // n0x01f6 c0x0000 (---------------) + I gle 0x0020ac06, // n0x01f7 c0x0000 (---------------) + I global 0x0020d785, // n0x01f8 c0x0000 (---------------) + I globo 0x00211cc2, // n0x01f9 c0x0000 (---------------) + I gm 0x0032a645, // n0x01fa c0x0000 (---------------) + I gmail 0x00213903, // n0x01fb c0x0000 (---------------) + I gmo 0x00216543, // n0x01fc c0x0000 (---------------) + I gmx 0x186082c2, // n0x01fd c0x0061 (n0x098b-n0x0991) + I gn 0x002ec247, // n0x01fe c0x0000 (---------------) + I godaddy 0x002f61c4, // n0x01ff c0x0000 (---------------) + I gold 0x002f61c9, // n0x0200 c0x0000 (---------------) + I goldpoint 0x00246dc4, // n0x0201 c0x0000 (---------------) + I golf 0x0026b283, // n0x0202 c0x0000 (---------------) + I goo 0x00315349, // n0x0203 c0x0000 (---------------) + I goodhands 0x0027b488, // n0x0204 c0x0000 (---------------) + I goodyear 0x00294284, // n0x0205 c0x0000 (---------------) + I goog 0x00294286, // n0x0206 c0x0000 (---------------) + I google 0x0029d043, // n0x0207 c0x0000 (---------------) + I gop 0x00212283, // n0x0208 c0x0000 (---------------) + I got 0x002d3e44, // n0x0209 c0x0000 (---------------) + I gotv 0x00264783, // n0x020a c0x0000 (---------------) + I gov 0x18ad19c2, // n0x020b c0x0062 (n0x0991-n0x0997) + I gp 0x002f7102, // n0x020c c0x0000 (---------------) + I gq 0x18e008c2, // n0x020d c0x0063 (n0x0997-n0x099d) + I gr 0x0030ee08, // n0x020e c0x0000 (---------------) + I grainger 0x00313a48, // n0x020f c0x0000 (---------------) + I graphics 0x00384806, // n0x0210 c0x0000 (---------------) + I gratis 0x00247b45, // n0x0211 c0x0000 (---------------) + I green 0x0021e8c5, // n0x0212 c0x0000 (---------------) + I gripe 0x0020fb45, // n0x0213 c0x0000 (---------------) + I group 0x0028fbc2, // n0x0214 c0x0000 (---------------) + I gs 0x1928a142, // n0x0215 c0x0064 (n0x099d-n0x09a4) + I gt 0x0160b102, // n0x0216 c0x0005 (---------------)* o I gu 0x0034cf48, // n0x0217 c0x0000 (---------------) + I guardian 0x00275485, // n0x0218 c0x0000 (---------------) + I gucci 0x002d9104, // n0x0219 c0x0000 (---------------) + I guge 0x00381a45, // n0x021a c0x0000 (---------------) + I guide 0x0022bc07, // n0x021b c0x0000 (---------------) + I guitars 0x0024af04, // n0x021c c0x0000 (---------------) + I guru 0x00212082, // n0x021d c0x0000 (---------------) + I gw 0x19601082, // n0x021e c0x0065 (n0x09a4-n0x09a7) + I gy 0x00211b47, // n0x021f c0x0000 (---------------) + I hamburg 0x0037a847, // n0x0220 c0x0000 (---------------) + I hangout 0x0035b4c4, // n0x0221 c0x0000 (---------------) + I haus 0x0028b0c3, // n0x0222 c0x0000 (---------------) + I hbo 0x00243e84, // n0x0223 c0x0000 (---------------) + I hdfc 0x00243e88, // n0x0224 c0x0000 (---------------) + I hdfcbank 0x00366f06, // n0x0225 c0x0000 (---------------) + I health 0x00366f0a, // n0x0226 c0x0000 (---------------) + I healthcare 0x00208404, // n0x0227 c0x0000 (---------------) + I help 0x00209748, // n0x0228 c0x0000 (---------------) + I helsinki 0x0024d144, // n0x0229 c0x0000 (---------------) + I here 0x00221146, // n0x022a c0x0000 (---------------) + I hermes 0x0028c404, // n0x022b c0x0000 (---------------) + I hgtv 0x0033b986, // n0x022c c0x0000 (---------------) + I hiphop 0x00326309, // n0x022d c0x0000 (---------------) + I hisamitsu 0x0029c147, // n0x022e c0x0000 (---------------) + I hitachi 0x002753c3, // n0x022f c0x0000 (---------------) + I hiv 0x19a0f882, // n0x0230 c0x0066 (n0x09a7-n0x09bf) + I hk 0x002659c3, // n0x0231 c0x0000 (---------------) + I hkt 0x0020b742, // n0x0232 c0x0000 (---------------) + I hm 0x19e168c2, // n0x0233 c0x0067 (n0x09bf-n0x09c5) + I hn 0x002d8486, // n0x0234 c0x0000 (---------------) + I hockey 0x00358948, // n0x0235 c0x0000 (---------------) + I holdings 0x0029e847, // n0x0236 c0x0000 (---------------) + I holiday 0x0026cd89, // n0x0237 c0x0000 (---------------) + I homedepot 0x00291e09, // n0x0238 c0x0000 (---------------) + I homegoods 0x0029fe45, // n0x0239 c0x0000 (---------------) + I homes 0x0029fe49, // n0x023a c0x0000 (---------------) + I homesense 0x002a1285, // n0x023b c0x0000 (---------------) + I honda 0x002a19c9, // n0x023c c0x0000 (---------------) + I honeywell 0x002a2785, // n0x023d c0x0000 (---------------) + I horse 0x002902c4, // n0x023e c0x0000 (---------------) + I host 0x002902c7, // n0x023f c0x0000 (---------------) + I hosting 0x0022de03, // n0x0240 c0x0000 (---------------) + I hot 0x002a3247, // n0x0241 c0x0000 (---------------) + I hoteles 0x002a3987, // n0x0242 c0x0000 (---------------) + I hotmail 0x0029bd45, // n0x0243 c0x0000 (---------------) + I house 0x0029b0c3, // n0x0244 c0x0000 (---------------) + I how 0x1a231342, // n0x0245 c0x0068 (n0x09c5-n0x09ca) + I hr 0x003817c4, // n0x0246 c0x0000 (---------------) + I hsbc 0x1a64a202, // n0x0247 c0x0069 (n0x09ca-n0x09db) + I ht 0x00256103, // n0x0248 c0x0000 (---------------) + I htc 0x1aa22f82, // n0x0249 c0x006a (n0x09db-n0x09fb) + I hu 0x002eed06, // n0x024a c0x0000 (---------------) + I hughes 0x002c1845, // n0x024b c0x0000 (---------------) + I hyatt 0x002a6987, // n0x024c c0x0000 (---------------) + I hyundai 0x002d4383, // n0x024d c0x0000 (---------------) + I ibm 0x0039b644, // n0x024e c0x0000 (---------------) + I icbc 0x00201343, // n0x024f c0x0000 (---------------) + I ice 0x0032fe43, // n0x0250 c0x0000 (---------------) + I icu 0x1ae03782, // n0x0251 c0x006b (n0x09fb-n0x0a06) + I id 0x1b600042, // n0x0252 c0x006d (n0x0a07-n0x0a09) + I ie 0x00361484, // n0x0253 c0x0000 (---------------) + I ieee 0x0022c103, // n0x0254 c0x0000 (---------------) + I ifm 0x00318105, // n0x0255 c0x0000 (---------------) + I iinet 0x00238885, // n0x0256 c0x0000 (---------------) + I ikano 0x1ba01b02, // n0x0257 c0x006e (n0x0a09-n0x0a11) + I il 0x1c207c02, // n0x0258 c0x0070 (n0x0a12-n0x0a19) + I im 0x00248946, // n0x0259 c0x0000 (---------------) + I imamat 0x00302744, // n0x025a c0x0000 (---------------) + I imdb 0x00207c04, // n0x025b c0x0000 (---------------) + I immo 0x00207c0a, // n0x025c c0x0000 (---------------) + I immobilien 0x1ca02082, // n0x025d c0x0072 (n0x0a1b-n0x0a28) + I in 0x0036280a, // n0x025e c0x0000 (---------------) + I industries 0x003a4dc8, // n0x025f c0x0000 (---------------) + I infiniti 0x1cfa4f84, // n0x0260 c0x0073 (n0x0a28-n0x0a32) + I info 0x0020ab83, // n0x0261 c0x0000 (---------------) + I ing 0x00209843, // n0x0262 c0x0000 (---------------) + I ink 0x00307dc9, // n0x0263 c0x0000 (---------------) + I institute 0x00236a09, // n0x0264 c0x0000 (---------------) + I insurance 0x0032f786, // n0x0265 c0x0000 (---------------) + I insure 0x1d267a43, // n0x0266 c0x0074 (n0x0a32-n0x0a33) + I int 0x002f6345, // n0x0267 c0x0000 (---------------) + I intel 0x002f810d, // n0x0268 c0x0000 (---------------) + I international 0x002eea06, // n0x0269 c0x0000 (---------------) + I intuit 0x0020938b, // n0x026a c0x0000 (---------------) + I investments 0x1d600542, // n0x026b c0x0075 (n0x0a33-n0x0a39) + I io 0x002637c8, // n0x026c c0x0000 (---------------) + I ipiranga 0x1da00a02, // n0x026d c0x0076 (n0x0a39-n0x0a3f) + I iq 0x1de04fc2, // n0x026e c0x0077 (n0x0a3f-n0x0a48) + I ir 0x0028ba85, // n0x026f c0x0000 (---------------) + I irish 0x1e2011c2, // n0x0270 c0x0078 (n0x0a48-n0x0a50) + I is 0x00254687, // n0x0271 c0x0000 (---------------) + I iselect 0x00277447, // n0x0272 c0x0000 (---------------) + I ismaili 0x0020cfc3, // n0x0273 c0x0000 (---------------) + I ist 0x0020cfc8, // n0x0274 c0x0000 (---------------) + I istanbul 0x1e602742, // n0x0275 c0x0079 (n0x0a50-n0x0bc1) + I it 0x0026db04, // n0x0276 c0x0000 (---------------) + I itau 0x0020da03, // n0x0277 c0x0000 (---------------) + I itv 0x0031ea45, // n0x0278 c0x0000 (---------------) + I iveco 0x00366703, // n0x0279 c0x0000 (---------------) + I iwc 0x002c1306, // n0x027a c0x0000 (---------------) + I jaguar 0x0031b0c4, // n0x027b c0x0000 (---------------) + I java 0x00234dc3, // n0x027c c0x0000 (---------------) + I jcb 0x00266103, // n0x027d c0x0000 (---------------) + I jcp 0x1ea07a82, // n0x027e c0x007a (n0x0bc1-n0x0bc4) + I je 0x0031ff44, // n0x027f c0x0000 (---------------) + I jeep 0x0034b405, // n0x0280 c0x0000 (---------------) + I jetzt 0x0035ca47, // n0x0281 c0x0000 (---------------) + I jewelry 0x00271d03, // n0x0282 c0x0000 (---------------) + I jio 0x002a6e03, // n0x0283 c0x0000 (---------------) + I jlc 0x002a7603, // n0x0284 c0x0000 (---------------) + I jll 0x016a76c2, // n0x0285 c0x0005 (---------------)* o I jm 0x002a76c3, // n0x0286 c0x0000 (---------------) + I jmp 0x002a7883, // n0x0287 c0x0000 (---------------) + I jnj 0x1ee014c2, // n0x0288 c0x007b (n0x0bc4-n0x0bcc) + I jo 0x002bc1c4, // n0x0289 c0x0000 (---------------) + I jobs 0x00274b06, // n0x028a c0x0000 (---------------) + I joburg 0x002014c3, // n0x028b c0x0000 (---------------) + I jot 0x002a7c03, // n0x028c c0x0000 (---------------) + I joy 0x1f2a8442, // n0x028d c0x007c (n0x0bcc-n0x0c3b) + I jp 0x002a8448, // n0x028e c0x0000 (---------------) + I jpmorgan 0x002a8e84, // n0x028f c0x0000 (---------------) + I jprs 0x00246fc6, // n0x0290 c0x0000 (---------------) + I juegos 0x002a9347, // n0x0291 c0x0000 (---------------) + I juniper 0x00216c06, // n0x0292 c0x0000 (---------------) + I kaufen 0x00399cc4, // n0x0293 c0x0000 (---------------) + I kddi 0x2ce017c2, // n0x0294 c0x00b3 (n0x12cf-n0x12d0)* o I ke 0x0022dccb, // n0x0295 c0x0000 (---------------) + I kerryhotels 0x002db70e, // n0x0296 c0x0000 (---------------) + I kerrylogistics 0x0022030f, // n0x0297 c0x0000 (---------------) + I kerryproperties 0x0022b1c3, // n0x0298 c0x0000 (---------------) + I kfh 0x2d6b1542, // n0x0299 c0x00b5 (n0x12d1-n0x12d7) + I kg 0x01616a42, // n0x029a c0x0005 (---------------)* o I kh 0x2da01cc2, // n0x029b c0x00b6 (n0x12d7-n0x12de) + I ki 0x002651c3, // n0x029c c0x0000 (---------------) + I kia 0x00233cc3, // n0x029d c0x0000 (---------------) + I kim 0x00376346, // n0x029e c0x0000 (---------------) + I kinder 0x0032c446, // n0x029f c0x0000 (---------------) + I kindle 0x00344787, // n0x02a0 c0x0000 (---------------) + I kitchen 0x002e2b84, // n0x02a1 c0x0000 (---------------) + I kiwi 0x2de37642, // n0x02a2 c0x00b7 (n0x12de-n0x12ef) + I km 0x2e24e8c2, // n0x02a3 c0x00b8 (n0x12ef-n0x12f3) + I kn 0x00224885, // n0x02a4 c0x0000 (---------------) + I koeln 0x002e1e07, // n0x02a5 c0x0000 (---------------) + I komatsu 0x002e3d86, // n0x02a6 c0x0000 (---------------) + I kosher 0x2e60e982, // n0x02a7 c0x00b9 (n0x12f3-n0x12f9) + I kp 0x0020e984, // n0x02a8 c0x0000 (---------------) + I kpmg 0x00365f43, // n0x02a9 c0x0000 (---------------) + I kpn 0x2ea07b42, // n0x02aa c0x00ba (n0x12f9-n0x1317) + I kr 0x0034a883, // n0x02ab c0x0000 (---------------) + I krd 0x0039e604, // n0x02ac c0x0000 (---------------) + I kred 0x002b1489, // n0x02ad c0x0000 (---------------) + I kuokgroup 0x016b8302, // n0x02ae c0x0005 (---------------)* o I kw 0x2ee306c2, // n0x02af c0x00bb (n0x1317-n0x131c) + I ky 0x00261786, // n0x02b0 c0x0000 (---------------) + I kyknet 0x002b9245, // n0x02b1 c0x0000 (---------------) + I kyoto 0x2f319c82, // n0x02b2 c0x00bc (n0x131c-n0x1322) + I kz 0x2f603102, // n0x02b3 c0x00bd (n0x1322-n0x132b) + I la 0x00330e47, // n0x02b4 c0x0000 (---------------) + I lacaixa 0x00289909, // n0x02b5 c0x0000 (---------------) + I ladbrokes 0x0034f28b, // n0x02b6 c0x0000 (---------------) + I lamborghini 0x00241405, // n0x02b7 c0x0000 (---------------) + I lamer 0x00368509, // n0x02b8 c0x0000 (---------------) + I lancaster 0x002bab46, // n0x02b9 c0x0000 (---------------) + I lancia 0x00252647, // n0x02ba c0x0000 (---------------) + I lancome 0x00205d84, // n0x02bb c0x0000 (---------------) + I land 0x002fecc9, // n0x02bc c0x0000 (---------------) + I landrover 0x00353947, // n0x02bd c0x0000 (---------------) + I lanxess 0x0027e807, // n0x02be c0x0000 (---------------) + I lasalle 0x00222643, // n0x02bf c0x0000 (---------------) + I lat 0x00225e86, // n0x02c0 c0x0000 (---------------) + I latino 0x002caf47, // n0x02c1 c0x0000 (---------------) + I latrobe 0x00266983, // n0x02c2 c0x0000 (---------------) + I law 0x00266986, // n0x02c3 c0x0000 (---------------) + I lawyer 0x2fa01b42, // n0x02c4 c0x00be (n0x132b-n0x1330) + I lb 0x2fe32842, // n0x02c5 c0x00bf (n0x1330-n0x1336) + I lc 0x00264a83, // n0x02c6 c0x0000 (---------------) + I lds 0x0027e945, // n0x02c7 c0x0000 (---------------) + I lease 0x002ae107, // n0x02c8 c0x0000 (---------------) + I leclerc 0x00373806, // n0x02c9 c0x0000 (---------------) + I lefrak 0x0032ab05, // n0x02ca c0x0000 (---------------) + I legal 0x00246d44, // n0x02cb c0x0000 (---------------) + I lego 0x002d7985, // n0x02cc c0x0000 (---------------) + I lexus 0x002df484, // n0x02cd c0x0000 (---------------) + I lgbt 0x30207d82, // n0x02ce c0x00c0 (n0x1336-n0x1337) + I li 0x00314847, // n0x02cf c0x0000 (---------------) + I liaison 0x002b6a84, // n0x02d0 c0x0000 (---------------) + I lidl 0x00236904, // n0x02d1 c0x0000 (---------------) + I life 0x0023690d, // n0x02d2 c0x0000 (---------------) + I lifeinsurance 0x00244f49, // n0x02d3 c0x0000 (---------------) + I lifestyle 0x002fa088, // n0x02d4 c0x0000 (---------------) + I lighting 0x00252284, // n0x02d5 c0x0000 (---------------) + I like 0x00342dc5, // n0x02d6 c0x0000 (---------------) + I lilly 0x002d4887, // n0x02d7 c0x0000 (---------------) + I limited 0x002d4c84, // n0x02d8 c0x0000 (---------------) + I limo 0x0030b887, // n0x02d9 c0x0000 (---------------) + I lincoln 0x00387305, // n0x02da c0x0000 (---------------) + I linde 0x003927c4, // n0x02db c0x0000 (---------------) + I link 0x002cdec5, // n0x02dc c0x0000 (---------------) + I lipsy 0x002594c4, // n0x02dd c0x0000 (---------------) + I live 0x002d7ac6, // n0x02de c0x0000 (---------------) + I living 0x002d4b85, // n0x02df c0x0000 (---------------) + I lixil 0x3060e942, // n0x02e0 c0x00c1 (n0x1337-n0x1346) + I lk 0x0020ed44, // n0x02e1 c0x0000 (---------------) + I loan 0x0020ed45, // n0x02e2 c0x0000 (---------------) + I loans 0x00370b46, // n0x02e3 c0x0000 (---------------) + I locker 0x0032ac45, // n0x02e4 c0x0000 (---------------) + I locus 0x002cc9c4, // n0x02e5 c0x0000 (---------------) + I loft 0x002bd303, // n0x02e6 c0x0000 (---------------) + I lol 0x00313c86, // n0x02e7 c0x0000 (---------------) + I london 0x00220f05, // n0x02e8 c0x0000 (---------------) + I lotte 0x00221885, // n0x02e9 c0x0000 (---------------) + I lotto 0x0034e204, // n0x02ea c0x0000 (---------------) + I love 0x00208483, // n0x02eb c0x0000 (---------------) + I lpl 0x0020848c, // n0x02ec c0x0000 (---------------) + I lplfinancial 0x30a82b42, // n0x02ed c0x00c2 (n0x1346-n0x134b) + I lr 0x30e04a42, // n0x02ee c0x00c3 (n0x134b-n0x134d) + I ls 0x31200d82, // n0x02ef c0x00c4 (n0x134d-n0x134f) + I lt 0x00314403, // n0x02f0 c0x0000 (---------------) + I ltd 0x00314404, // n0x02f1 c0x0000 (---------------) + I ltda 0x31602ac2, // n0x02f2 c0x00c5 (n0x134f-n0x1350) + I lu 0x002dbac8, // n0x02f3 c0x0000 (---------------) + I lundbeck 0x002dc0c5, // n0x02f4 c0x0000 (---------------) + I lupin 0x0022c504, // n0x02f5 c0x0000 (---------------) + I luxe 0x00231bc6, // n0x02f6 c0x0000 (---------------) + I luxury 0x31a0dd82, // n0x02f7 c0x00c6 (n0x1350-n0x1359) + I lv 0x31e3bb82, // n0x02f8 c0x00c7 (n0x1359-n0x1362) + I ly 0x32200182, // n0x02f9 c0x00c8 (n0x1362-n0x1368) + I ma 0x00349785, // n0x02fa c0x0000 (---------------) + I macys 0x00310646, // n0x02fb c0x0000 (---------------) + I madrid 0x002fe204, // n0x02fc c0x0000 (---------------) + I maif 0x00205b06, // n0x02fd c0x0000 (---------------) + I maison 0x0024de86, // n0x02fe c0x0000 (---------------) + I makeup 0x002021c3, // n0x02ff c0x0000 (---------------) + I man 0x0036330a, // n0x0300 c0x0000 (---------------) + I management 0x00234805, // n0x0301 c0x0000 (---------------) + I mango 0x0024f0c6, // n0x0302 c0x0000 (---------------) + I market 0x002e5489, // n0x0303 c0x0000 (---------------) + I marketing 0x0024f0c7, // n0x0304 c0x0000 (---------------) + I markets 0x0023b588, // n0x0305 c0x0000 (---------------) + I marriott 0x00209b89, // n0x0306 c0x0000 (---------------) + I marshalls 0x002b5dc8, // n0x0307 c0x0000 (---------------) + I maserati 0x002af106, // n0x0308 c0x0000 (---------------) + I mattel 0x002349c3, // n0x0309 c0x0000 (---------------) + I mba 0x32618742, // n0x030a c0x00c9 (n0x1368-n0x136a) + I mc 0x003756c3, // n0x030b c0x0000 (---------------) + I mcd 0x003756c9, // n0x030c c0x0000 (---------------) + I mcdonalds 0x00319208, // n0x030d c0x0000 (---------------) + I mckinsey 0x32a46c82, // n0x030e c0x00ca (n0x136a-n0x136b) + I md 0x32e09502, // n0x030f c0x00cb (n0x136b-n0x1378) + I me 0x00220d43, // n0x0310 c0x0000 (---------------) + I med 0x003a15c5, // n0x0311 c0x0000 (---------------) + I media 0x002629c4, // n0x0312 c0x0000 (---------------) + I meet 0x002da389, // n0x0313 c0x0000 (---------------) + I melbourne 0x002ac644, // n0x0314 c0x0000 (---------------) + I meme 0x00399a08, // n0x0315 c0x0000 (---------------) + I memorial 0x00209503, // n0x0316 c0x0000 (---------------) + I men 0x0033a2c4, // n0x0317 c0x0000 (---------------) + I menu 0x00218903, // n0x0318 c0x0000 (---------------) + I meo 0x00236847, // n0x0319 c0x0000 (---------------) + I metlife 0x3320ea02, // n0x031a c0x00cc (n0x1378-n0x1381) + I mg 0x00253dc2, // n0x031b c0x0000 (---------------) + I mh 0x0022ac45, // n0x031c c0x0000 (---------------) + I miami 0x00262d89, // n0x031d c0x0000 (---------------) + I microsoft 0x00214d03, // n0x031e c0x0000 (---------------) + I mil 0x00275144, // n0x031f c0x0000 (---------------) + I mini 0x002f80c4, // n0x0320 c0x0000 (---------------) + I mint 0x00239243, // n0x0321 c0x0000 (---------------) + I mit 0x00276cca, // n0x0322 c0x0000 (---------------) + I mitsubishi 0x337626c2, // n0x0323 c0x00cd (n0x1381-n0x1389) + I mk 0x33a0ed02, // n0x0324 c0x00ce (n0x1389-n0x1390) + I ml 0x002bbd83, // n0x0325 c0x0000 (---------------) + I mlb 0x00365083, // n0x0326 c0x0000 (---------------) + I mls 0x01607c42, // n0x0327 c0x0005 (---------------)* o I mm 0x00369a83, // n0x0328 c0x0000 (---------------) + I mma 0x33e1e242, // n0x0329 c0x00cf (n0x1390-n0x1394) + I mn 0x0021e244, // n0x032a c0x0000 (---------------) + I mnet 0x34207c82, // n0x032b c0x00d0 (n0x1394-n0x1399) + I mo 0x34607c84, // n0x032c c0x00d1 (n0x1399-n0x139a) + I mobi 0x002d09c6, // n0x032d c0x0000 (---------------) + I mobily 0x00263cc4, // n0x032e c0x0000 (---------------) + I moda 0x002473c3, // n0x032f c0x0000 (---------------) + I moe 0x0027a6c3, // n0x0330 c0x0000 (---------------) + I moi 0x0022a283, // n0x0331 c0x0000 (---------------) + I mom 0x0023e086, // n0x0332 c0x0000 (---------------) + I monash 0x002c2f45, // n0x0333 c0x0000 (---------------) + I money 0x002bcf47, // n0x0334 c0x0000 (---------------) + I monster 0x00252509, // n0x0335 c0x0000 (---------------) + I montblanc 0x002c0245, // n0x0336 c0x0000 (---------------) + I mopar 0x002c2e86, // n0x0337 c0x0000 (---------------) + I mormon 0x002c3488, // n0x0338 c0x0000 (---------------) + I mortgage 0x002c3686, // n0x0339 c0x0000 (---------------) + I moscow 0x00271604, // n0x033a c0x0000 (---------------) + I moto 0x0029348b, // n0x033b c0x0000 (---------------) + I motorcycles 0x002c4d83, // n0x033c c0x0000 (---------------) + I mov 0x002c4d85, // n0x033d c0x0000 (---------------) + I movie 0x002c4ec8, // n0x033e c0x0000 (---------------) + I movistar 0x00226cc2, // n0x033f c0x0000 (---------------) + I mp 0x00331142, // n0x0340 c0x0000 (---------------) + I mq 0x34a436c2, // n0x0341 c0x00d2 (n0x139a-n0x139c) + I mr 0x34e0bbc2, // n0x0342 c0x00d3 (n0x139c-n0x13a1) + I ms 0x0026a3c3, // n0x0343 c0x0000 (---------------) + I msd 0x352643c2, // n0x0344 c0x00d4 (n0x13a1-n0x13a5) + I mt 0x002643c3, // n0x0345 c0x0000 (---------------) + I mtn 0x002c51c4, // n0x0346 c0x0000 (---------------) + I mtpc 0x002c5703, // n0x0347 c0x0000 (---------------) + I mtr 0x35a078c2, // n0x0348 c0x00d6 (n0x13a6-n0x13ad) + I mu 0x002c730b, // n0x0349 c0x0000 (---------------) + I multichoice 0x35eca1c6, // n0x034a c0x00d7 (n0x13ad-n0x15d1) + I museum 0x00235506, // n0x034b c0x0000 (---------------) + I mutual 0x002ca808, // n0x034c c0x0000 (---------------) + I mutuelle 0x3625cc82, // n0x034d c0x00d8 (n0x15d1-n0x15df) + I mv 0x3660bf42, // n0x034e c0x00d9 (n0x15df-n0x15ea) + I mw 0x36a16582, // n0x034f c0x00da (n0x15ea-n0x15f0) + I mx 0x36e65142, // n0x0350 c0x00db (n0x15f0-n0x15f8) + I my 0x37212b42, // n0x0351 c0x00dc (n0x15f8-n0x15f9)* o I mz 0x00212b4b, // n0x0352 c0x0000 (---------------) + I mzansimagic 0x37601f42, // n0x0353 c0x00dd (n0x15f9-n0x160a) + I na 0x00218fc3, // n0x0354 c0x0000 (---------------) + I nab 0x0039af45, // n0x0355 c0x0000 (---------------) + I nadex 0x00304146, // n0x0356 c0x0000 (---------------) + I nagoya 0x37a0ff84, // n0x0357 c0x00de (n0x160a-n0x160c) + I name 0x003a2dc7, // n0x0358 c0x0000 (---------------) + I naspers 0x0039a9ca, // n0x0359 c0x0000 (---------------) + I nationwide 0x002d5746, // n0x035a c0x0000 (---------------) + I natura 0x0037bd04, // n0x035b c0x0000 (---------------) + I navy 0x00256283, // n0x035c c0x0000 (---------------) + I nba 0x38608642, // n0x035d c0x00e1 (n0x160e-n0x160f) + I nc 0x00201e02, // n0x035e c0x0000 (---------------) + I ne 0x00239903, // n0x035f c0x0000 (---------------) + I nec 0x38a1e283, // n0x0360 c0x00e2 (n0x160f-n0x1643) + I net 0x00319b07, // n0x0361 c0x0000 (---------------) + I netbank 0x002d4a87, // n0x0362 c0x0000 (---------------) + I netflix 0x0024fa07, // n0x0363 c0x0000 (---------------) + I network 0x00225bc7, // n0x0364 c0x0000 (---------------) + I neustar 0x00226b83, // n0x0365 c0x0000 (---------------) + I new 0x002cedca, // n0x0366 c0x0000 (---------------) + I newholland 0x00229684, // n0x0367 c0x0000 (---------------) + I news 0x00246884, // n0x0368 c0x0000 (---------------) + I next 0x0024688a, // n0x0369 c0x0000 (---------------) + I nextdirect 0x00265585, // n0x036a c0x0000 (---------------) + I nexus 0x39e30b02, // n0x036b c0x00e7 (n0x164b-n0x1655) + I nf 0x0024a0c3, // n0x036c c0x0000 (---------------) + I nfl 0x3a2006c2, // n0x036d c0x00e8 (n0x1655-n0x165e) + I ng 0x002006c3, // n0x036e c0x0000 (---------------) + I ngo 0x00265983, // n0x036f c0x0000 (---------------) + I nhk 0x3aa01fc2, // n0x0370 c0x00ea (n0x165f-n0x166d) o I ni 0x00283144, // n0x0371 c0x0000 (---------------) + I nico 0x0021cb04, // n0x0372 c0x0000 (---------------) + I nike 0x00207e45, // n0x0373 c0x0000 (---------------) + I nikon 0x002c5485, // n0x0374 c0x0000 (---------------) + I ninja 0x00229ac6, // n0x0375 c0x0000 (---------------) + I nissan 0x002ae686, // n0x0376 c0x0000 (---------------) + I nissay 0x3ae03842, // n0x0377 c0x00eb (n0x166d-n0x1670) + I nl 0x3b200842, // n0x0378 c0x00ec (n0x1670-n0x1946) + I no 0x00311c85, // n0x0379 c0x0000 (---------------) + I nokia 0x00235212, // n0x037a c0x0000 (---------------) + I northwesternmutual 0x00359c46, // n0x037b c0x0000 (---------------) + I norton 0x0021fc03, // n0x037c c0x0000 (---------------) + I now 0x00296286, // n0x037d c0x0000 (---------------) + I nowruz 0x0021fc05, // n0x037e c0x0000 (---------------) + I nowtv 0x0160d402, // n0x037f c0x0005 (---------------)* o I np 0x436a0842, // n0x0380 c0x010d (n0x196e-n0x1975) + I nr 0x002cfc03, // n0x0381 c0x0000 (---------------) + I nra 0x00351e43, // n0x0382 c0x0000 (---------------) + I nrw 0x0036e003, // n0x0383 c0x0000 (---------------) + I ntt 0x43a020c2, // n0x0384 c0x010e (n0x1975-n0x1978) + I nu 0x0036aa83, // n0x0385 c0x0000 (---------------) + I nyc 0x43e10a42, // n0x0386 c0x010f (n0x1978-n0x1988) + I nz 0x00207cc3, // n0x0387 c0x0000 (---------------) + I obi 0x002bc208, // n0x0388 c0x0000 (---------------) + I observer 0x00203e03, // n0x0389 c0x0000 (---------------) + I off 0x00228f46, // n0x038a c0x0000 (---------------) + I office 0x0038fc07, // n0x038b c0x0000 (---------------) + I okinawa 0x0020f9c6, // n0x038c c0x0000 (---------------) + I olayan 0x0020f9cb, // n0x038d c0x0000 (---------------) + I olayangroup 0x0037bc47, // n0x038e c0x0000 (---------------) + I oldnavy 0x003815c4, // n0x038f c0x0000 (---------------) + I ollo 0x44604b02, // n0x0390 c0x0111 (n0x1989-n0x1992) + I om 0x002dbf45, // n0x0391 c0x0000 (---------------) + I omega 0x0020c803, // n0x0392 c0x0000 (---------------) + I one 0x0024e643, // n0x0393 c0x0000 (---------------) + I ong 0x00310ac3, // n0x0394 c0x0000 (---------------) + I onl 0x00310ac6, // n0x0395 c0x0000 (---------------) + I online 0x0037c20a, // n0x0396 c0x0000 (---------------) + I onyourside 0x00286f83, // n0x0397 c0x0000 (---------------) + I ooo 0x00236084, // n0x0398 c0x0000 (---------------) + I open 0x0033c306, // n0x0399 c0x0000 (---------------) + I oracle 0x00390346, // n0x039a c0x0000 (---------------) + I orange 0x44a23a43, // n0x039b c0x0112 (n0x1992-n0x19cf) + I org 0x002a8507, // n0x039c c0x0000 (---------------) + I organic 0x002b07cd, // n0x039d c0x0000 (---------------) + I orientexpress 0x0036fc07, // n0x039e c0x0000 (---------------) + I origins 0x002931c5, // n0x039f c0x0000 (---------------) + I osaka 0x00261986, // n0x03a0 c0x0000 (---------------) + I otsuka 0x00220f43, // n0x03a1 c0x0000 (---------------) + I ott 0x0020ae43, // n0x03a2 c0x0000 (---------------) + I ovh 0x46203942, // n0x03a3 c0x0118 (n0x1a0c-n0x1a17) + I pa 0x00337604, // n0x03a4 c0x0000 (---------------) + I page 0x0023b7cc, // n0x03a5 c0x0000 (---------------) + I pamperedchef 0x00245749, // n0x03a6 c0x0000 (---------------) + I panasonic 0x0032b887, // n0x03a7 c0x0000 (---------------) + I panerai 0x00266185, // n0x03a8 c0x0000 (---------------) + I paris 0x0037af44, // n0x03a9 c0x0000 (---------------) + I pars 0x0029d0c8, // n0x03aa c0x0000 (---------------) + I partners 0x0029eb45, // n0x03ab c0x0000 (---------------) + I parts 0x002a7745, // n0x03ac c0x0000 (---------------) + I party 0x002b1689, // n0x03ad c0x0000 (---------------) + I passagens 0x002b7243, // n0x03ae c0x0000 (---------------) + I pay 0x002b7244, // n0x03af c0x0000 (---------------) + I payu 0x002c5244, // n0x03b0 c0x0000 (---------------) + I pccw 0x466087c2, // n0x03b1 c0x0119 (n0x1a17-n0x1a1f) + I pe 0x002087c3, // n0x03b2 c0x0000 (---------------) + I pet 0x46ad3b02, // n0x03b3 c0x011a (n0x1a1f-n0x1a22) + I pf 0x002d3b06, // n0x03b4 c0x0000 (---------------) + I pfizer 0x0166b902, // n0x03b5 c0x0005 (---------------)* o I pg 0x46e00982, // n0x03b6 c0x011b (n0x1a22-n0x1a2a) + I ph 0x00349688, // n0x03b7 c0x0000 (---------------) + I pharmacy 0x002cde07, // n0x03b8 c0x0000 (---------------) + I philips 0x00294dc5, // n0x03b9 c0x0000 (---------------) + I photo 0x002ce48b, // n0x03ba c0x0000 (---------------) + I photography 0x002cb606, // n0x03bb c0x0000 (---------------) + I photos 0x002ce686, // n0x03bc c0x0000 (---------------) + I physio 0x002ce806, // n0x03bd c0x0000 (---------------) + I piaget 0x00373c84, // n0x03be c0x0000 (---------------) + I pics 0x002cf046, // n0x03bf c0x0000 (---------------) + I pictet 0x002cf548, // n0x03c0 c0x0000 (---------------) + I pictures 0x0023bf83, // n0x03c1 c0x0000 (---------------) + I pid 0x00218303, // n0x03c2 c0x0000 (---------------) + I pin 0x00218304, // n0x03c3 c0x0000 (---------------) + I ping 0x002cfcc4, // n0x03c4 c0x0000 (---------------) + I pink 0x002d0247, // n0x03c5 c0x0000 (---------------) + I pioneer 0x002d0cc5, // n0x03c6 c0x0000 (---------------) + I pizza 0x472d0e02, // n0x03c7 c0x011c (n0x1a2a-n0x1a38) + I pk 0x47607502, // n0x03c8 c0x011d (n0x1a38-n0x1add) + I pl 0x00207505, // n0x03c9 c0x0000 (---------------) + I place 0x00295444, // n0x03ca c0x0000 (---------------) + I play 0x002d2b0b, // n0x03cb c0x0000 (---------------) + I playstation 0x002d3c88, // n0x03cc c0x0000 (---------------) + I plumbing 0x002d6544, // n0x03cd c0x0000 (---------------) + I plus 0x0020e9c2, // n0x03ce c0x0000 (---------------) + I pm 0x47e6b702, // n0x03cf c0x011f (n0x1b0c-n0x1b11) + I pn 0x002a8cc3, // n0x03d0 c0x0000 (---------------) + I pnc 0x002d6984, // n0x03d1 c0x0000 (---------------) + I pohl 0x002d6a85, // n0x03d2 c0x0000 (---------------) + I poker 0x002d6fc7, // n0x03d3 c0x0000 (---------------) + I politie 0x002d8c44, // n0x03d4 c0x0000 (---------------) + I porn 0x0035b5c4, // n0x03d5 c0x0000 (---------------) + I post 0x482052c2, // n0x03d6 c0x0120 (n0x1b11-n0x1b1e) + I pr 0x00352a49, // n0x03d7 c0x0000 (---------------) + I pramerica 0x002d9645, // n0x03d8 c0x0000 (---------------) + I praxi 0x002416c5, // n0x03d9 c0x0000 (---------------) + I press 0x002da2c5, // n0x03da c0x0000 (---------------) + I prime 0x48620443, // n0x03db c0x0121 (n0x1b1e-n0x1b25) + I pro 0x002dabc4, // n0x03dc c0x0000 (---------------) + I prod 0x002dabcb, // n0x03dd c0x0000 (---------------) + I productions 0x002db004, // n0x03de c0x0000 (---------------) + I prof 0x002db28b, // n0x03df c0x0000 (---------------) + I progressive 0x002dcd05, // n0x03e0 c0x0000 (---------------) + I promo 0x0022044a, // n0x03e1 c0x0000 (---------------) + I properties 0x002dd508, // n0x03e2 c0x0000 (---------------) + I property 0x002dd70a, // n0x03e3 c0x0000 (---------------) + I protection 0x002dd983, // n0x03e4 c0x0000 (---------------) + I pru 0x002dd98a, // n0x03e5 c0x0000 (---------------) + I prudential 0x48a23982, // n0x03e6 c0x0122 (n0x1b25-n0x1b2c) + I ps 0x48e6ae82, // n0x03e7 c0x0123 (n0x1b2c-n0x1b35) + I pt 0x00297d83, // n0x03e8 c0x0000 (---------------) + I pub 0x492de982, // n0x03e9 c0x0124 (n0x1b35-n0x1b3b) + I pw 0x002de983, // n0x03ea c0x0000 (---------------) + I pwc 0x49727902, // n0x03eb c0x0125 (n0x1b3b-n0x1b42) + I py 0x49b0da42, // n0x03ec c0x0126 (n0x1b42-n0x1b4b) + I qa 0x002df304, // n0x03ed c0x0000 (---------------) + I qpon 0x00219d86, // n0x03ee c0x0000 (---------------) + I quebec 0x00205845, // n0x03ef c0x0000 (---------------) + I quest 0x002df8c3, // n0x03f0 c0x0000 (---------------) + I qvc 0x003001c6, // n0x03f1 c0x0000 (---------------) + I racing 0x00223c84, // n0x03f2 c0x0000 (---------------) + I raid 0x49e04902, // n0x03f3 c0x0127 (n0x1b4b-n0x1b4f) + I re 0x002cd844, // n0x03f4 c0x0000 (---------------) + I read 0x002bd4ca, // n0x03f5 c0x0000 (---------------) + I realestate 0x0033cd47, // n0x03f6 c0x0000 (---------------) + I realtor 0x002c1686, // n0x03f7 c0x0000 (---------------) + I realty 0x00226e07, // n0x03f8 c0x0000 (---------------) + I recipes 0x0023b903, // n0x03f9 c0x0000 (---------------) + I red 0x0039e648, // n0x03fa c0x0000 (---------------) + I redstone 0x0032b2cb, // n0x03fb c0x0000 (---------------) + I redumbrella 0x0035aac5, // n0x03fc c0x0000 (---------------) + I rehab 0x002c8845, // n0x03fd c0x0000 (---------------) + I reise 0x002c8846, // n0x03fe c0x0000 (---------------) + I reisen 0x0032f884, // n0x03ff c0x0000 (---------------) + I reit 0x003195c8, // n0x0400 c0x0000 (---------------) + I reliance 0x00204903, // n0x0401 c0x0000 (---------------) + I ren 0x00204904, // n0x0402 c0x0000 (---------------) + I rent 0x00204907, // n0x0403 c0x0000 (---------------) + I rentals 0x002b1e46, // n0x0404 c0x0000 (---------------) + I repair 0x002f0e46, // n0x0405 c0x0000 (---------------) + I report 0x00297d0a, // n0x0406 c0x0000 (---------------) + I republican 0x00246744, // n0x0407 c0x0000 (---------------) + I rest 0x00361d0a, // n0x0408 c0x0000 (---------------) + I restaurant 0x003371c6, // n0x0409 c0x0000 (---------------) + I review 0x003371c7, // n0x040a c0x0000 (---------------) + I reviews 0x00251087, // n0x040b c0x0000 (---------------) + I rexroth 0x0026c744, // n0x040c c0x0000 (---------------) + I rich 0x0026c749, // n0x040d c0x0000 (---------------) + I richardli 0x0025c885, // n0x040e c0x0000 (---------------) + I ricoh 0x00341c4b, // n0x040f c0x0000 (---------------) + I rightathome 0x0024a3c3, // n0x0410 c0x0000 (---------------) + I ril 0x00209083, // n0x0411 c0x0000 (---------------) + I rio 0x0021e903, // n0x0412 c0x0000 (---------------) + I rip 0x4a200f82, // n0x0413 c0x0128 (n0x1b4f-n0x1b5b) + I ro 0x0027c286, // n0x0414 c0x0000 (---------------) + I rocher 0x0029ae45, // n0x0415 c0x0000 (---------------) + I rocks 0x002b2845, // n0x0416 c0x0000 (---------------) + I rodeo 0x00206d86, // n0x0417 c0x0000 (---------------) + I rogers 0x00357ec4, // n0x0418 c0x0000 (---------------) + I room 0x4a606e82, // n0x0419 c0x0129 (n0x1b5b-n0x1b62) + I rs 0x00206e84, // n0x041a c0x0000 (---------------) + I rsvp 0x4aa0efc2, // n0x041b c0x012a (n0x1b62-n0x1be5) + I ru 0x002312c4, // n0x041c c0x0000 (---------------) + I ruhr 0x00221b83, // n0x041d c0x0000 (---------------) + I run 0x4af1b942, // n0x041e c0x012b (n0x1be5-n0x1bee) + I rw 0x00335c83, // n0x041f c0x0000 (---------------) + I rwe 0x00366846, // n0x0420 c0x0000 (---------------) + I ryukyu 0x4b200642, // n0x0421 c0x012c (n0x1bee-n0x1bf6) + I sa 0x00305748, // n0x0422 c0x0000 (---------------) + I saarland 0x00397c84, // n0x0423 c0x0000 (---------------) + I safe 0x00397c86, // n0x0424 c0x0000 (---------------) + I safety 0x002d4206, // n0x0425 c0x0000 (---------------) + I sakura 0x00252bc4, // n0x0426 c0x0000 (---------------) + I sale 0x00313c05, // n0x0427 c0x0000 (---------------) + I salon 0x00387008, // n0x0428 c0x0000 (---------------) + I samsclub 0x00387507, // n0x0429 c0x0000 (---------------) + I samsung 0x0024b047, // n0x042a c0x0000 (---------------) + I sandvik 0x0024b04f, // n0x042b c0x0000 (---------------) + I sandvikcoromant 0x0028dd46, // n0x042c c0x0000 (---------------) + I sanofi 0x00214a03, // n0x042d c0x0000 (---------------) + I sap 0x00214a04, // n0x042e c0x0000 (---------------) + I sapo 0x00220e44, // n0x042f c0x0000 (---------------) + I sarl 0x00225503, // n0x0430 c0x0000 (---------------) + I sas 0x00221284, // n0x0431 c0x0000 (---------------) + I save 0x0036ae84, // n0x0432 c0x0000 (---------------) + I saxo 0x4b6239c2, // n0x0433 c0x012d (n0x1bf6-n0x1bfb) + I sb 0x00283ec3, // n0x0434 c0x0000 (---------------) + I sbi 0x0037f383, // n0x0435 c0x0000 (---------------) + I sbs 0x4ba13402, // n0x0436 c0x012e (n0x1bfb-n0x1c00) + I sc 0x002307c3, // n0x0437 c0x0000 (---------------) + I sca 0x0033a883, // n0x0438 c0x0000 (---------------) + I scb 0x0021340a, // n0x0439 c0x0000 (---------------) + I schaeffler 0x0034de07, // n0x043a c0x0000 (---------------) + I schmidt 0x00381c8c, // n0x043b c0x0000 (---------------) + I scholarships 0x00381f46, // n0x043c c0x0000 (---------------) + I school 0x0022af46, // n0x043d c0x0000 (---------------) + I schule 0x0022bd87, // n0x043e c0x0000 (---------------) + I schwarz 0x0022f207, // n0x043f c0x0000 (---------------) + I science 0x0023cf49, // n0x0440 c0x0000 (---------------) + I scjohnson 0x0021ad84, // n0x0441 c0x0000 (---------------) + I scor 0x00392404, // n0x0442 c0x0000 (---------------) + I scot 0x4be56cc2, // n0x0443 c0x012f (n0x1c00-n0x1c08) + I sd 0x4c201242, // n0x0444 c0x0130 (n0x1c08-n0x1c31) + I se 0x00310084, // n0x0445 c0x0000 (---------------) + I seat 0x00315ec6, // n0x0446 c0x0000 (---------------) + I secure 0x0022f688, // n0x0447 c0x0000 (---------------) + I security 0x0027ea04, // n0x0448 c0x0000 (---------------) + I seek 0x002546c6, // n0x0449 c0x0000 (---------------) + I select 0x002c6cc5, // n0x044a c0x0000 (---------------) + I sener 0x00201248, // n0x044b c0x0000 (---------------) + I services 0x00205383, // n0x044c c0x0000 (---------------) + I ses 0x00241e45, // n0x044d c0x0000 (---------------) + I seven 0x00244dc3, // n0x044e c0x0000 (---------------) + I sew 0x002417c3, // n0x044f c0x0000 (---------------) + I sex 0x002417c4, // n0x0450 c0x0000 (---------------) + I sexy 0x00248603, // n0x0451 c0x0000 (---------------) + I sfr 0x4c665682, // n0x0452 c0x0131 (n0x1c31-n0x1c38) + I sg 0x4ca02802, // n0x0453 c0x0132 (n0x1c38-n0x1c3f) + I sh 0x0024a289, // n0x0454 c0x0000 (---------------) + I shangrila 0x0024cb05, // n0x0455 c0x0000 (---------------) + I sharp 0x00250904, // n0x0456 c0x0000 (---------------) + I shaw 0x002518c5, // n0x0457 c0x0000 (---------------) + I shell 0x00211584, // n0x0458 c0x0000 (---------------) + I shia 0x002f2807, // n0x0459 c0x0000 (---------------) + I shiksha 0x0037f285, // n0x045a c0x0000 (---------------) + I shoes 0x002a9986, // n0x045b c0x0000 (---------------) + I shouji 0x002aadc4, // n0x045c c0x0000 (---------------) + I show 0x002ac4c8, // n0x045d c0x0000 (---------------) + I showtime 0x002b1887, // n0x045e c0x0000 (---------------) + I shriram 0x4ce09802, // n0x045f c0x0133 (n0x1c3f-n0x1c40) + I si 0x00352e04, // n0x0460 c0x0000 (---------------) + I silk 0x002ed044, // n0x0461 c0x0000 (---------------) + I sina 0x0027f207, // n0x0462 c0x0000 (---------------) + I singles 0x0023d984, // n0x0463 c0x0000 (---------------) + I site 0x00254a42, // n0x0464 c0x0000 (---------------) + I sj 0x4d208882, // n0x0465 c0x0134 (n0x1c40-n0x1c41) + I sk 0x00244243, // n0x0466 c0x0000 (---------------) + I ski 0x00376304, // n0x0467 c0x0000 (---------------) + I skin 0x00230683, // n0x0468 c0x0000 (---------------) + I sky 0x00230685, // n0x0469 c0x0000 (---------------) + I skype 0x4d61fa02, // n0x046a c0x0135 (n0x1c41-n0x1c46) + I sl 0x002c71c5, // n0x046b c0x0000 (---------------) + I sling 0x00214cc2, // n0x046c c0x0000 (---------------) + I sm 0x00363d05, // n0x046d c0x0000 (---------------) + I smart 0x00358b05, // n0x046e c0x0000 (---------------) + I smile 0x4da0ce82, // n0x046f c0x0136 (n0x1c46-n0x1c4e) + I sn 0x00215b84, // n0x0470 c0x0000 (---------------) + I sncf 0x4de05bc2, // n0x0471 c0x0137 (n0x1c4e-n0x1c51) + I so 0x002d5386, // n0x0472 c0x0000 (---------------) + I soccer 0x0029ef06, // n0x0473 c0x0000 (---------------) + I social 0x00262ec8, // n0x0474 c0x0000 (---------------) + I softbank 0x002b2e48, // n0x0475 c0x0000 (---------------) + I software 0x002eec84, // n0x0476 c0x0000 (---------------) + I sohu 0x002d9ac5, // n0x0477 c0x0000 (---------------) + I solar 0x002eee49, // n0x0478 c0x0000 (---------------) + I solutions 0x0024e604, // n0x0479 c0x0000 (---------------) + I song 0x0037c1c4, // n0x047a c0x0000 (---------------) + I sony 0x00239143, // n0x047b c0x0000 (---------------) + I soy 0x002046c5, // n0x047c c0x0000 (---------------) + I space 0x0036bfc7, // n0x047d c0x0000 (---------------) + I spiegel 0x00294504, // n0x047e c0x0000 (---------------) + I spot 0x0032734d, // n0x047f c0x0000 (---------------) + I spreadbetting 0x00329142, // n0x0480 c0x0000 (---------------) + I sr 0x00329143, // n0x0481 c0x0000 (---------------) + I srl 0x00331bc3, // n0x0482 c0x0000 (---------------) + I srt 0x4e201942, // n0x0483 c0x0138 (n0x1c51-n0x1c5d) + I st 0x00377dc5, // n0x0484 c0x0000 (---------------) + I stada 0x0022adc7, // n0x0485 c0x0000 (---------------) + I staples 0x00225c84, // n0x0486 c0x0000 (---------------) + I star 0x00225c87, // n0x0487 c0x0000 (---------------) + I starhub 0x00209d89, // n0x0488 c0x0000 (---------------) + I statebank 0x002bd609, // n0x0489 c0x0000 (---------------) + I statefarm 0x002e8287, // n0x048a c0x0000 (---------------) + I statoil 0x002708c3, // n0x048b c0x0000 (---------------) + I stc 0x002708c8, // n0x048c c0x0000 (---------------) + I stcgroup 0x00292389, // n0x048d c0x0000 (---------------) + I stockholm 0x00356447, // n0x048e c0x0000 (---------------) + I storage 0x003758c5, // n0x048f c0x0000 (---------------) + I store 0x002e0086, // n0x0490 c0x0000 (---------------) + I studio 0x002e0205, // n0x0491 c0x0000 (---------------) + I study 0x00245045, // n0x0492 c0x0000 (---------------) + I style 0x4e601142, // n0x0493 c0x0139 (n0x1c5d-n0x1c7d) + I su 0x0031a7c5, // n0x0494 c0x0000 (---------------) + I sucks 0x002b4a8a, // n0x0495 c0x0000 (---------------) + I supersport 0x002b9448, // n0x0496 c0x0000 (---------------) + I supplies 0x002a0a46, // n0x0497 c0x0000 (---------------) + I supply 0x002dcf47, // n0x0498 c0x0000 (---------------) + I support 0x002404c4, // n0x0499 c0x0000 (---------------) + I surf 0x00293ac7, // n0x049a c0x0000 (---------------) + I surgery 0x002e2d06, // n0x049b c0x0000 (---------------) + I suzuki 0x4ea06ec2, // n0x049c c0x013a (n0x1c7d-n0x1c82) + I sv 0x00370846, // n0x049d c0x0000 (---------------) + I swatch 0x002e56ca, // n0x049e c0x0000 (---------------) + I swiftcover 0x002e6085, // n0x049f c0x0000 (---------------) + I swiss 0x4eee6902, // n0x04a0 c0x013b (n0x1c82-n0x1c83) + I sx 0x4f27c482, // n0x04a1 c0x013c (n0x1c83-n0x1c89) + I sy 0x00320146, // n0x04a2 c0x0000 (---------------) + I sydney 0x002a5888, // n0x04a3 c0x0000 (---------------) + I symantec 0x0037aa07, // n0x04a4 c0x0000 (---------------) + I systems 0x4f604502, // n0x04a5 c0x013d (n0x1c89-n0x1c8c) + I sz 0x0020bcc3, // n0x04a6 c0x0000 (---------------) + I tab 0x003a1e46, // n0x04a7 c0x0000 (---------------) + I taipei 0x0021db84, // n0x04a8 c0x0000 (---------------) + I talk 0x0038fac6, // n0x04a9 c0x0000 (---------------) + I taobao 0x002399c6, // n0x04aa c0x0000 (---------------) + I target 0x00386dca, // n0x04ab c0x0000 (---------------) + I tatamotors 0x0039c145, // n0x04ac c0x0000 (---------------) + I tatar 0x0021edc6, // n0x04ad c0x0000 (---------------) + I tattoo 0x00222e83, // n0x04ae c0x0000 (---------------) + I tax 0x00222e84, // n0x04af c0x0000 (---------------) + I taxi 0x00205102, // n0x04b0 c0x0000 (---------------) + I tc 0x003026c3, // n0x04b1 c0x0000 (---------------) + I tci 0x4fa03d02, // n0x04b2 c0x013e (n0x1c8c-n0x1c8d) + I td 0x002c5383, // n0x04b3 c0x0000 (---------------) + I tdk 0x00362a84, // n0x04b4 c0x0000 (---------------) + I team 0x002a59c4, // n0x04b5 c0x0000 (---------------) + I tech 0x002a59ca, // n0x04b6 c0x0000 (---------------) + I technology 0x00227983, // n0x04b7 c0x0000 (---------------) + I tel 0x002807c8, // n0x04b8 c0x0000 (---------------) + I telecity 0x00307f8a, // n0x04b9 c0x0000 (---------------) + I telefonica 0x0023a987, // n0x04ba c0x0000 (---------------) + I temasek 0x002e9206, // n0x04bb c0x0000 (---------------) + I tennis 0x00322b84, // n0x04bc c0x0000 (---------------) + I teva 0x00288942, // n0x04bd c0x0000 (---------------) + I tf 0x002235c2, // n0x04be c0x0000 (---------------) + I tg 0x4fe07482, // n0x04bf c0x013f (n0x1c8d-n0x1c94) + I th 0x00243e43, // n0x04c0 c0x0000 (---------------) + I thd 0x00250e47, // n0x04c1 c0x0000 (---------------) + I theater 0x00300487, // n0x04c2 c0x0000 (---------------) + I theatre 0x0034ce8b, // n0x04c3 c0x0000 (---------------) + I theguardian 0x00349544, // n0x04c4 c0x0000 (---------------) + I tiaa 0x002eb247, // n0x04c5 c0x0000 (---------------) + I tickets 0x002d70c6, // n0x04c6 c0x0000 (---------------) + I tienda 0x00397a47, // n0x04c7 c0x0000 (---------------) + I tiffany 0x0034dd44, // n0x04c8 c0x0000 (---------------) + I tips 0x00333605, // n0x04c9 c0x0000 (---------------) + I tires 0x002b4f45, // n0x04ca c0x0000 (---------------) + I tirol 0x50231ec2, // n0x04cb c0x0140 (n0x1c94-n0x1ca3) + I tj 0x00363546, // n0x04cc c0x0000 (---------------) + I tjmaxx 0x00231ec3, // n0x04cd c0x0000 (---------------) + I tjx 0x00218842, // n0x04ce c0x0000 (---------------) + I tk 0x00237606, // n0x04cf c0x0000 (---------------) + I tkmaxx 0x50613e42, // n0x04d0 c0x0141 (n0x1ca3-n0x1ca4) + I tl 0x50a00142, // n0x04d1 c0x0142 (n0x1ca4-n0x1cac) + I tm 0x00200145, // n0x04d2 c0x0000 (---------------) + I tmall 0x50e2a482, // n0x04d3 c0x0143 (n0x1cac-n0x1cc0) + I tn 0x51203b82, // n0x04d4 c0x0144 (n0x1cc0-n0x1cc6) + I to 0x0032d645, // n0x04d5 c0x0000 (---------------) + I today 0x0033f685, // n0x04d6 c0x0000 (---------------) + I tokyo 0x0021ee85, // n0x04d7 c0x0000 (---------------) + I tools 0x00240f43, // n0x04d8 c0x0000 (---------------) + I top 0x00275cc5, // n0x04d9 c0x0000 (---------------) + I toray 0x002cb6c7, // n0x04da c0x0000 (---------------) + I toshiba 0x00255945, // n0x04db c0x0000 (---------------) + I total 0x002f3f85, // n0x04dc c0x0000 (---------------) + I tours 0x002afb44, // n0x04dd c0x0000 (---------------) + I town 0x0025d5c6, // n0x04de c0x0000 (---------------) + I toyota 0x00265a44, // n0x04df c0x0000 (---------------) + I toys 0x00212302, // n0x04e0 c0x0000 (---------------) + I tp 0x51602b82, // n0x04e1 c0x0145 (n0x1cc6-n0x1cdb) + I tr 0x0025e585, // n0x04e2 c0x0000 (---------------) + I trade 0x0029de47, // n0x04e3 c0x0000 (---------------) + I trading 0x002f97c8, // n0x04e4 c0x0000 (---------------) + I training 0x0029b806, // n0x04e5 c0x0000 (---------------) + I travel 0x0029b80d, // n0x04e6 c0x0000 (---------------) + I travelchannel 0x002a2dc9, // n0x04e7 c0x0000 (---------------) + I travelers 0x002a2dd2, // n0x04e8 c0x0000 (---------------) + I travelersinsurance 0x0031f7c5, // n0x04e9 c0x0000 (---------------) + I trust 0x0033f943, // n0x04ea c0x0000 (---------------) + I trv 0x5220b642, // n0x04eb c0x0148 (n0x1cdd-n0x1cee) + I tt 0x002ddf84, // n0x04ec c0x0000 (---------------) + I tube 0x002eea83, // n0x04ed c0x0000 (---------------) + I tui 0x002e6d85, // n0x04ee c0x0000 (---------------) + I tunes 0x002e7ac5, // n0x04ef c0x0000 (---------------) + I tushu 0x5260da42, // n0x04f0 c0x0149 (n0x1cee-n0x1cf2) + I tv 0x00360143, // n0x04f1 c0x0000 (---------------) + I tvs 0x52a42e02, // n0x04f2 c0x014a (n0x1cf2-n0x1d00) + I tw 0x52e1e302, // n0x04f3 c0x014b (n0x1d00-n0x1d0c) + I tz 0x53222fc2, // n0x04f4 c0x014c (n0x1d0c-n0x1d5b) + I ua 0x0032e5c5, // n0x04f5 c0x0000 (---------------) + I ubank 0x00395b43, // n0x04f6 c0x0000 (---------------) + I ubs 0x00239808, // n0x04f7 c0x0000 (---------------) + I uconnect 0x536025c2, // n0x04f8 c0x014d (n0x1d5b-n0x1d64) + I ug 0x53a00bc2, // n0x04f9 c0x014e (n0x1d64-n0x1d6f) + I uk 0x00283106, // n0x04fa c0x0000 (---------------) + I unicom 0x003179ca, // n0x04fb c0x0000 (---------------) + I university 0x0020c343, // n0x04fc c0x0000 (---------------) + I uno 0x00236f03, // n0x04fd c0x0000 (---------------) + I uol 0x002cad43, // n0x04fe c0x0000 (---------------) + I ups 0x54601102, // n0x04ff c0x0151 (n0x1d71-n0x1db0) + I us 0x62a02102, // n0x0500 c0x018a (n0x1e53-n0x1e59) + I uy 0x6320a142, // n0x0501 c0x018c (n0x1e5a-n0x1e5e) + I uz 0x002000c2, // n0x0502 c0x0000 (---------------) + I va 0x00370649, // n0x0503 c0x0000 (---------------) + I vacations 0x002b7744, // n0x0504 c0x0000 (---------------) + I vana 0x00283b88, // n0x0505 c0x0000 (---------------) + I vanguard 0x636df902, // n0x0506 c0x018d (n0x1e5e-n0x1e64) + I vc 0x63a01d82, // n0x0507 c0x018e (n0x1e64-n0x1e75) + I ve 0x0034e285, // n0x0508 c0x0000 (---------------) + I vegas 0x00233688, // n0x0509 c0x0000 (---------------) + I ventures 0x002e5888, // n0x050a c0x0000 (---------------) + I verisign 0x0038e84c, // n0x050b c0x0000 (---------------) + I versicherung 0x0023a8c3, // n0x050c c0x0000 (---------------) + I vet 0x00258e82, // n0x050d c0x0000 (---------------) + I vg 0x63e01302, // n0x050e c0x018f (n0x1e75-n0x1e7a) + I vi 0x002c06c6, // n0x050f c0x0000 (---------------) + I viajes 0x002ea085, // n0x0510 c0x0000 (---------------) + I video 0x00308d43, // n0x0511 c0x0000 (---------------) + I vig 0x0022d5c6, // n0x0512 c0x0000 (---------------) + I viking 0x002ea1c6, // n0x0513 c0x0000 (---------------) + I villas 0x00238f43, // n0x0514 c0x0000 (---------------) + I vin 0x002ecf83, // n0x0515 c0x0000 (---------------) + I vip 0x002edf46, // n0x0516 c0x0000 (---------------) + I virgin 0x002ee4c4, // n0x0517 c0x0000 (---------------) + I visa 0x00277cc6, // n0x0518 c0x0000 (---------------) + I vision 0x002c4f45, // n0x0519 c0x0000 (---------------) + I vista 0x002ee84a, // n0x051a c0x0000 (---------------) + I vistaprint 0x00235684, // n0x051b c0x0000 (---------------) + I viva 0x002ef584, // n0x051c c0x0000 (---------------) + I vivo 0x0034374a, // n0x051d c0x0000 (---------------) + I vlaanderen 0x64202fc2, // n0x051e c0x0190 (n0x1e7a-n0x1e87) + I vn 0x00267745, // n0x051f c0x0000 (---------------) + I vodka 0x002f13ca, // n0x0520 c0x0000 (---------------) + I volkswagen 0x002f3c84, // n0x0521 c0x0000 (---------------) + I vote 0x002f3d86, // n0x0522 c0x0000 (---------------) + I voting 0x002f3f04, // n0x0523 c0x0000 (---------------) + I voto 0x00225986, // n0x0524 c0x0000 (---------------) + I voyage 0x6462a3c2, // n0x0525 c0x0191 (n0x1e87-n0x1e8b) + I vu 0x002c0fc6, // n0x0526 c0x0000 (---------------) + I vuelos 0x002c2085, // n0x0527 c0x0000 (---------------) + I wales 0x0039bfc7, // n0x0528 c0x0000 (---------------) + I walmart 0x00200d06, // n0x0529 c0x0000 (---------------) + I walter 0x0022bf84, // n0x052a c0x0000 (---------------) + I wang 0x0034eb07, // n0x052b c0x0000 (---------------) + I wanggou 0x00363246, // n0x052c c0x0000 (---------------) + I warman 0x002a7205, // n0x052d c0x0000 (---------------) + I watch 0x0039f8c7, // n0x052e c0x0000 (---------------) + I watches 0x0038adc7, // n0x052f c0x0000 (---------------) + I weather 0x0038adce, // n0x0530 c0x0000 (---------------) + I weatherchannel 0x002292c6, // n0x0531 c0x0000 (---------------) + I webcam 0x0030b745, // n0x0532 c0x0000 (---------------) + I weber 0x002bb247, // n0x0533 c0x0000 (---------------) + I website 0x002e43c3, // n0x0534 c0x0000 (---------------) + I wed 0x003425c7, // n0x0535 c0x0000 (---------------) + I wedding 0x0020c0c5, // n0x0536 c0x0000 (---------------) + I weibo 0x0020eb84, // n0x0537 c0x0000 (---------------) + I weir 0x00229902, // n0x0538 c0x0000 (---------------) + I wf 0x00382187, // n0x0539 c0x0000 (---------------) + I whoswho 0x002e2c04, // n0x053a c0x0000 (---------------) + I wien 0x0032c3c4, // n0x053b c0x0000 (---------------) + I wiki 0x00253c4b, // n0x053c c0x0000 (---------------) + I williamhill 0x0021b643, // n0x053d c0x0000 (---------------) + I win 0x0027cf87, // n0x053e c0x0000 (---------------) + I windows 0x0021b644, // n0x053f c0x0000 (---------------) + I wine 0x002aac47, // n0x0540 c0x0000 (---------------) + I winners 0x0022a943, // n0x0541 c0x0000 (---------------) + I wme 0x0032150d, // n0x0542 c0x0000 (---------------) + I wolterskluwer 0x00378608, // n0x0543 c0x0000 (---------------) + I woodside 0x0024fac4, // n0x0544 c0x0000 (---------------) + I work 0x00382645, // n0x0545 c0x0000 (---------------) + I works 0x002f6805, // n0x0546 c0x0000 (---------------) + I world 0x002f47c3, // n0x0547 c0x0000 (---------------) + I wow 0x64a044c2, // n0x0548 c0x0192 (n0x1e8b-n0x1e92) + I ws 0x002f56c3, // n0x0549 c0x0000 (---------------) + I wtc 0x002f5ec3, // n0x054a c0x0000 (---------------) + I wtf 0x002165c4, // n0x054b c0x0000 (---------------) + I xbox 0x00273ec5, // n0x054c c0x0000 (---------------) + I xerox 0x00216687, // n0x054d c0x0000 (---------------) + I xfinity 0x00222f06, // n0x054e c0x0000 (---------------) + I xihuan 0x003627c3, // n0x054f c0x0000 (---------------) + I xin 0x00231f4b, // n0x0550 c0x0000 (---------------) + I xn--11b4c3d 0x0023774b, // n0x0551 c0x0000 (---------------) + I xn--1ck2e1b 0x0026240b, // n0x0552 c0x0000 (---------------) + I xn--1qqw23a 0x00273fca, // n0x0553 c0x0000 (---------------) + I xn--30rr7y 0x002a0d8b, // n0x0554 c0x0000 (---------------) + I xn--3bst00m 0x002d174b, // n0x0555 c0x0000 (---------------) + I xn--3ds443g 0x002ce18c, // n0x0556 c0x0000 (---------------) + I xn--3e0b707e 0x002e6951, // n0x0557 c0x0000 (---------------) + I xn--3oq18vl8pn36a 0x0032f24a, // n0x0558 c0x0000 (---------------) + I xn--3pxu8k 0x0034660b, // n0x0559 c0x0000 (---------------) + I xn--42c2d9a 0x0039f24b, // n0x055a c0x0000 (---------------) + I xn--45brj9c 0x003a128a, // n0x055b c0x0000 (---------------) + I xn--45q11c 0x002f6c0a, // n0x055c c0x0000 (---------------) + I xn--4gbrim 0x002f6fcd, // n0x055d c0x0000 (---------------) + I xn--4gq48lf9j 0x002f878e, // n0x055e c0x0000 (---------------) + I xn--54b7fta0cc 0x002f8ccb, // n0x055f c0x0000 (---------------) + I xn--55qw42g 0x002f8f8a, // n0x0560 c0x0000 (---------------) + I xn--55qx5d 0x002fb091, // n0x0561 c0x0000 (---------------) + I xn--5su34j936bgsg 0x002fb4ca, // n0x0562 c0x0000 (---------------) + I xn--5tzm5g 0x002fb9cb, // n0x0563 c0x0000 (---------------) + I xn--6frz82g 0x002fbf0e, // n0x0564 c0x0000 (---------------) + I xn--6qq986b3xl 0x002fc88c, // n0x0565 c0x0000 (---------------) + I xn--80adxhks 0x002fcf8b, // n0x0566 c0x0000 (---------------) + I xn--80ao21a 0x002fd24e, // n0x0567 c0x0000 (---------------) + I xn--80aqecdr1a 0x002fd5cc, // n0x0568 c0x0000 (---------------) + I xn--80asehdb 0x0030070a, // n0x0569 c0x0000 (---------------) + I xn--80aswg 0x0030154c, // n0x056a c0x0000 (---------------) + I xn--8y0a063a 0x64f0184a, // n0x056b c0x0193 (n0x1e92-n0x1e98) + I xn--90a3ac 0x00304f89, // n0x056c c0x0000 (---------------) + I xn--90ais 0x0030648a, // n0x056d c0x0000 (---------------) + I xn--9dbq2a 0x0030670a, // n0x056e c0x0000 (---------------) + I xn--9et52u 0x0030698b, // n0x056f c0x0000 (---------------) + I xn--9krt00a 0x0030a94e, // n0x0570 c0x0000 (---------------) + I xn--b4w605ferd 0x0030acd1, // n0x0571 c0x0000 (---------------) + I xn--bck1b9a5dre4c 0x003121c9, // n0x0572 c0x0000 (---------------) + I xn--c1avg 0x0031240a, // n0x0573 c0x0000 (---------------) + I xn--c2br7g 0x0031324b, // n0x0574 c0x0000 (---------------) + I xn--cck2b3b 0x00314f0a, // n0x0575 c0x0000 (---------------) + I xn--cg4bki 0x00315856, // n0x0576 c0x0000 (---------------) + I xn--clchc0ea0b2g2a9gcd 0x0031704b, // n0x0577 c0x0000 (---------------) + I xn--czr694b 0x0031ad0a, // n0x0578 c0x0000 (---------------) + I xn--czrs0t 0x0031b54a, // n0x0579 c0x0000 (---------------) + I xn--czru2d 0x0031e40b, // n0x057a c0x0000 (---------------) + I xn--d1acj3b 0x0031f249, // n0x057b c0x0000 (---------------) + I xn--d1alf 0x00321e8d, // n0x057c c0x0000 (---------------) + I xn--eckvdtc9d 0x0032278b, // n0x057d c0x0000 (---------------) + I xn--efvy88h 0x0032348b, // n0x057e c0x0000 (---------------) + I xn--estv75g 0x00323e4b, // n0x057f c0x0000 (---------------) + I xn--fct429k 0x00324409, // n0x0580 c0x0000 (---------------) + I xn--fhbei 0x00324a4e, // n0x0581 c0x0000 (---------------) + I xn--fiq228c5hs 0x00324e8a, // n0x0582 c0x0000 (---------------) + I xn--fiq64b 0x0032710a, // n0x0583 c0x0000 (---------------) + I xn--fiqs8s 0x0032768a, // n0x0584 c0x0000 (---------------) + I xn--fiqz9s 0x00327e4b, // n0x0585 c0x0000 (---------------) + I xn--fjq720a 0x0032868b, // n0x0586 c0x0000 (---------------) + I xn--flw351e 0x0032894d, // n0x0587 c0x0000 (---------------) + I xn--fpcrj9c3d 0x00329d8d, // n0x0588 c0x0000 (---------------) + I xn--fzc2c9e2c 0x0032a2d0, // n0x0589 c0x0000 (---------------) + I xn--fzys8d69uvgm 0x0032a78b, // n0x058a c0x0000 (---------------) + I xn--g2xx48c 0x0032cccc, // n0x058b c0x0000 (---------------) + I xn--gckr3f0f 0x0032d78b, // n0x058c c0x0000 (---------------) + I xn--gecrj9c 0x0033094b, // n0x058d c0x0000 (---------------) + I xn--gk3at1e 0x00332c8b, // n0x058e c0x0000 (---------------) + I xn--h2brj9c 0x0033ddcb, // n0x058f c0x0000 (---------------) + I xn--hxt814e 0x0033e84f, // n0x0590 c0x0000 (---------------) + I xn--i1b6b1a6a2e 0x0033ec0b, // n0x0591 c0x0000 (---------------) + I xn--imr513n 0x0033fc0a, // n0x0592 c0x0000 (---------------) + I xn--io0a7i 0x00340509, // n0x0593 c0x0000 (---------------) + I xn--j1aef 0x003408c9, // n0x0594 c0x0000 (---------------) + I xn--j1amh 0x00340ecb, // n0x0595 c0x0000 (---------------) + I xn--j6w193g 0x0034118e, // n0x0596 c0x0000 (---------------) + I xn--jlq61u9w7b 0x00343dcb, // n0x0597 c0x0000 (---------------) + I xn--jvr189m 0x003451cf, // n0x0598 c0x0000 (---------------) + I xn--kcrx77d1x4a 0x00346ecb, // n0x0599 c0x0000 (---------------) + I xn--kprw13d 0x0034718b, // n0x059a c0x0000 (---------------) + I xn--kpry57d 0x0034744b, // n0x059b c0x0000 (---------------) + I xn--kpu716f 0x00347a0a, // n0x059c c0x0000 (---------------) + I xn--kput3i 0x0034ee89, // n0x059d c0x0000 (---------------) + I xn--l1acc 0x003512cf, // n0x059e c0x0000 (---------------) + I xn--lgbbat1ad8j 0x0035618c, // n0x059f c0x0000 (---------------) + I xn--mgb2ddes 0x0035660c, // n0x05a0 c0x0000 (---------------) + I xn--mgb9awbf 0x00356bce, // n0x05a1 c0x0000 (---------------) + I xn--mgba3a3ejt 0x0035808f, // n0x05a2 c0x0000 (---------------) + I xn--mgba3a4f16a 0x0035844e, // n0x05a3 c0x0000 (---------------) + I xn--mgba3a4fra 0x00358f50, // n0x05a4 c0x0000 (---------------) + I xn--mgba7c0bbn0a 0x0035934f, // n0x05a5 c0x0000 (---------------) + I xn--mgbaakc7dvf 0x0035a0ce, // n0x05a6 c0x0000 (---------------) + I xn--mgbaam7a8h 0x0035accc, // n0x05a7 c0x0000 (---------------) + I xn--mgbab2bd 0x0035afd2, // n0x05a8 c0x0000 (---------------) + I xn--mgbai9a5eva00b 0x0035c651, // n0x05a9 c0x0000 (---------------) + I xn--mgbai9azgqp6j 0x0035cc0e, // n0x05aa c0x0000 (---------------) + I xn--mgbayh7gpa 0x0035d04e, // n0x05ab c0x0000 (---------------) + I xn--mgbb9fbpob 0x0035d58e, // n0x05ac c0x0000 (---------------) + I xn--mgbbh1a71e 0x0035d90f, // n0x05ad c0x0000 (---------------) + I xn--mgbc0a9azcg 0x0035dcce, // n0x05ae c0x0000 (---------------) + I xn--mgbca7dzdo 0x0035e1d3, // n0x05af c0x0000 (---------------) + I xn--mgberp4a5d4a87g 0x0035e691, // n0x05b0 c0x0000 (---------------) + I xn--mgberp4a5d4ar 0x0035eace, // n0x05b1 c0x0000 (---------------) + I xn--mgbi4ecexp 0x0035ef4c, // n0x05b2 c0x0000 (---------------) + I xn--mgbpl2fh 0x0035f393, // n0x05b3 c0x0000 (---------------) + I xn--mgbqly7c0a67fbc 0x0035fb10, // n0x05b4 c0x0000 (---------------) + I xn--mgbqly7cvafr 0x0036038c, // n0x05b5 c0x0000 (---------------) + I xn--mgbt3dhd 0x0036068c, // n0x05b6 c0x0000 (---------------) + I xn--mgbtf8fl 0x00360bcb, // n0x05b7 c0x0000 (---------------) + I xn--mgbtx2b 0x0036108e, // n0x05b8 c0x0000 (---------------) + I xn--mgbx4cd0ab 0x0036158b, // n0x05b9 c0x0000 (---------------) + I xn--mix082f 0x0036194b, // n0x05ba c0x0000 (---------------) + I xn--mix891f 0x00362e4c, // n0x05bb c0x0000 (---------------) + I xn--mk1bu44c 0x0036b2ca, // n0x05bc c0x0000 (---------------) + I xn--mxtq1m 0x0036b68c, // n0x05bd c0x0000 (---------------) + I xn--ngbc5azd 0x0036b98c, // n0x05be c0x0000 (---------------) + I xn--ngbe9e0a 0x0036ca4b, // n0x05bf c0x0000 (---------------) + I xn--nnx388a 0x0036cd08, // n0x05c0 c0x0000 (---------------) + I xn--node 0x0036d1c9, // n0x05c1 c0x0000 (---------------) + I xn--nqv7f 0x0036d1cf, // n0x05c2 c0x0000 (---------------) + I xn--nqv7fs00ema 0x0036eb4b, // n0x05c3 c0x0000 (---------------) + I xn--nyqy26a 0x0036f70a, // n0x05c4 c0x0000 (---------------) + I xn--o3cw4h 0x00370ccc, // n0x05c5 c0x0000 (---------------) + I xn--ogbpf8fl 0x00372a49, // n0x05c6 c0x0000 (---------------) + I xn--p1acf 0x00372cc8, // n0x05c7 c0x0000 (---------------) + I xn--p1ai 0x00372ecb, // n0x05c8 c0x0000 (---------------) + I xn--pbt977c 0x00373fcb, // n0x05c9 c0x0000 (---------------) + I xn--pgbs0dh 0x00374bca, // n0x05ca c0x0000 (---------------) + I xn--pssy2u 0x00374e4b, // n0x05cb c0x0000 (---------------) + I xn--q9jyb4c 0x0037544c, // n0x05cc c0x0000 (---------------) + I xn--qcka1pmc 0x00376088, // n0x05cd c0x0000 (---------------) + I xn--qxam 0x0037880b, // n0x05ce c0x0000 (---------------) + I xn--rhqv96g 0x0037b40b, // n0x05cf c0x0000 (---------------) + I xn--rovu88b 0x0037ee0b, // n0x05d0 c0x0000 (---------------) + I xn--s9brj9c 0x003809cb, // n0x05d1 c0x0000 (---------------) + I xn--ses554g 0x0038a94b, // n0x05d2 c0x0000 (---------------) + I xn--t60b56a 0x0038ac09, // n0x05d3 c0x0000 (---------------) + I xn--tckwe 0x0038b14d, // n0x05d4 c0x0000 (---------------) + I xn--tiq49xqyj 0x003909ca, // n0x05d5 c0x0000 (---------------) + I xn--unup4y 0x00391917, // n0x05d6 c0x0000 (---------------) + I xn--vermgensberater-ctb 0x00392d58, // n0x05d7 c0x0000 (---------------) + I xn--vermgensberatung-pwb 0x003964c9, // n0x05d8 c0x0000 (---------------) + I xn--vhquv 0x003976cb, // n0x05d9 c0x0000 (---------------) + I xn--vuq861b 0x00398c14, // n0x05da c0x0000 (---------------) + I xn--w4r85el8fhu5dnra 0x0039910b, // n0x05db c0x0000 (---------------) + I xn--w4rs40l 0x0039968a, // n0x05dc c0x0000 (---------------) + I xn--wgbh1c 0x0039b98a, // n0x05dd c0x0000 (---------------) + I xn--wgbl6a 0x0039bc0b, // n0x05de c0x0000 (---------------) + I xn--xhq521b 0x0039c710, // n0x05df c0x0000 (---------------) + I xn--xkc2al3hye2a 0x0039cb11, // n0x05e0 c0x0000 (---------------) + I xn--xkc2dl3a5ee0h 0x0039da4a, // n0x05e1 c0x0000 (---------------) + I xn--y9a3aq 0x0039e84d, // n0x05e2 c0x0000 (---------------) + I xn--yfro4i67o 0x0039ef4d, // n0x05e3 c0x0000 (---------------) + I xn--ygbi2ammx 0x003a170b, // n0x05e4 c0x0000 (---------------) + I xn--zfr164b 0x003a5186, // n0x05e5 c0x0000 (---------------) + I xperia 0x00363643, // n0x05e6 c0x0000 (---------------) + I xxx 0x00241843, // n0x05e7 c0x0000 (---------------) + I xyz 0x00303906, // n0x05e8 c0x0000 (---------------) + I yachts 0x00286ec5, // n0x05e9 c0x0000 (---------------) + I yahoo 0x002c3b07, // n0x05ea c0x0000 (---------------) + I yamaxun 0x0032f106, // n0x05eb c0x0000 (---------------) + I yandex 0x0161bbc2, // n0x05ec c0x0005 (---------------)* o I ye 0x002f5809, // n0x05ed c0x0000 (---------------) + I yodobashi 0x002fffc4, // n0x05ee c0x0000 (---------------) + I yoga 0x00353348, // n0x05ef c0x0000 (---------------) + I yokohama 0x00243d83, // n0x05f0 c0x0000 (---------------) + I you 0x002ddec7, // n0x05f1 c0x0000 (---------------) + I youtube 0x00217f82, // n0x05f2 c0x0000 (---------------) + I yt 0x002a69c3, // n0x05f3 c0x0000 (---------------) + I yun 0x6520a182, // n0x05f4 c0x0194 (n0x1e98-n0x1ea9) o I za 0x002bf146, // n0x05f5 c0x0000 (---------------) + I zappos 0x002bfcc4, // n0x05f6 c0x0000 (---------------) + I zara 0x00337c84, // n0x05f7 c0x0000 (---------------) + I zero 0x0022e0c3, // n0x05f8 c0x0000 (---------------) + I zip 0x0022e0c5, // n0x05f9 c0x0000 (---------------) + I zippo 0x016f6982, // n0x05fa c0x0005 (---------------)* o I zm 0x002d6884, // n0x05fb c0x0000 (---------------) + I zone 0x0026c687, // n0x05fc c0x0000 (---------------) + I zuerich 0x0165b942, // n0x05fd c0x0005 (---------------)* o I zw 0x0022d0c3, // n0x05fe c0x0000 (---------------) + I com 0x002325c3, // n0x05ff c0x0000 (---------------) + I edu 0x00264783, // n0x0600 c0x0000 (---------------) + I gov 0x00214d03, // n0x0601 c0x0000 (---------------) + I mil 0x0021e283, // n0x0602 c0x0000 (---------------) + I net 0x00223a43, // n0x0603 c0x0000 (---------------) + I org 0x0020f543, // n0x0604 c0x0000 (---------------) + I nom 0x00203982, // n0x0605 c0x0000 (---------------) + I ac 0x000f4e08, // n0x0606 c0x0000 (---------------) + blogspot 0x00203dc2, // n0x0607 c0x0000 (---------------) + I co 0x00264783, // n0x0608 c0x0000 (---------------) + I gov 0x00214d03, // n0x0609 c0x0000 (---------------) + I mil 0x0021e283, // n0x060a c0x0000 (---------------) + I net 0x00223a43, // n0x060b c0x0000 (---------------) + I org 0x00213403, // n0x060c c0x0000 (---------------) + I sch 0x0030f696, // n0x060d c0x0000 (---------------) + I accident-investigation 0x003111d3, // n0x060e c0x0000 (---------------) + I accident-prevention 0x002eb0c9, // n0x060f c0x0000 (---------------) + I aerobatic 0x0039a548, // n0x0610 c0x0000 (---------------) + I aeroclub 0x002dbdc9, // n0x0611 c0x0000 (---------------) + I aerodrome 0x002f1546, // n0x0612 c0x0000 (---------------) + I agents 0x0033bb90, // n0x0613 c0x0000 (---------------) + I air-surveillance 0x002b1f13, // n0x0614 c0x0000 (---------------) + I air-traffic-control 0x0032b9c8, // n0x0615 c0x0000 (---------------) + I aircraft 0x00272387, // n0x0616 c0x0000 (---------------) + I airline 0x0027dc87, // n0x0617 c0x0000 (---------------) + I airport 0x0029910a, // n0x0618 c0x0000 (---------------) + I airtraffic 0x002b1b89, // n0x0619 c0x0000 (---------------) + I ambulance 0x00369049, // n0x061a c0x0000 (---------------) + I amusement 0x002c7fcb, // n0x061b c0x0000 (---------------) + I association 0x0031dac6, // n0x061c c0x0000 (---------------) + I author 0x002af4ca, // n0x061d c0x0000 (---------------) + I ballooning 0x00220246, // n0x061e c0x0000 (---------------) + I broker 0x002ffbc3, // n0x061f c0x0000 (---------------) + I caa 0x002ec185, // n0x0620 c0x0000 (---------------) + I cargo 0x0034d9c8, // n0x0621 c0x0000 (---------------) + I catering 0x002d544d, // n0x0622 c0x0000 (---------------) + I certification 0x0033b74c, // n0x0623 c0x0000 (---------------) + I championship 0x002c1d47, // n0x0624 c0x0000 (---------------) + I charter 0x00351b4d, // n0x0625 c0x0000 (---------------) + I civilaviation 0x00387104, // n0x0626 c0x0000 (---------------) + I club 0x00230a8a, // n0x0627 c0x0000 (---------------) + I conference 0x002313ca, // n0x0628 c0x0000 (---------------) + I consultant 0x0023188a, // n0x0629 c0x0000 (---------------) + I consulting 0x002b2207, // n0x062a c0x0000 (---------------) + I control 0x0023c607, // n0x062b c0x0000 (---------------) + I council 0x0023e444, // n0x062c c0x0000 (---------------) + I crew 0x002289c6, // n0x062d c0x0000 (---------------) + I design 0x0031de84, // n0x062e c0x0000 (---------------) + I dgca 0x002f1f48, // n0x062f c0x0000 (---------------) + I educator 0x002382c9, // n0x0630 c0x0000 (---------------) + I emergency 0x00364cc6, // n0x0631 c0x0000 (---------------) + I engine 0x00364cc8, // n0x0632 c0x0000 (---------------) + I engineer 0x0024244d, // n0x0633 c0x0000 (---------------) + I entertainment 0x002bd849, // n0x0634 c0x0000 (---------------) + I equipment 0x0039b008, // n0x0635 c0x0000 (---------------) + I exchange 0x00241647, // n0x0636 c0x0000 (---------------) + I express 0x0020038a, // n0x0637 c0x0000 (---------------) + I federation 0x0024a106, // n0x0638 c0x0000 (---------------) + I flight 0x00255fc7, // n0x0639 c0x0000 (---------------) + I freight 0x00235f44, // n0x063a c0x0000 (---------------) + I fuel 0x0024cd07, // n0x063b c0x0000 (---------------) + I gliding 0x0026478a, // n0x063c c0x0000 (---------------) + I government 0x002fa24e, // n0x063d c0x0000 (---------------) + I groundhandling 0x0020fb45, // n0x063e c0x0000 (---------------) + I group 0x002f450b, // n0x063f c0x0000 (---------------) + I hanggliding 0x002ec4c9, // n0x0640 c0x0000 (---------------) + I homebuilt 0x00236a09, // n0x0641 c0x0000 (---------------) + I insurance 0x00277287, // n0x0642 c0x0000 (---------------) + I journal 0x00393c0a, // n0x0643 c0x0000 (---------------) + I journalist 0x0027f147, // n0x0644 c0x0000 (---------------) + I leasing 0x002db849, // n0x0645 c0x0000 (---------------) + I logistics 0x00390088, // n0x0646 c0x0000 (---------------) + I magazine 0x002679cb, // n0x0647 c0x0000 (---------------) + I maintenance 0x003a15c5, // n0x0648 c0x0000 (---------------) + I media 0x002f9f4a, // n0x0649 c0x0000 (---------------) + I microlight 0x0029cb89, // n0x064a c0x0000 (---------------) + I modelling 0x00308cca, // n0x064b c0x0000 (---------------) + I navigation 0x002c02cb, // n0x064c c0x0000 (---------------) + I parachuting 0x0024cc0b, // n0x064d c0x0000 (---------------) + I paragliding 0x002c7d55, // n0x064e c0x0000 (---------------) + I passenger-association 0x002cf9c5, // n0x064f c0x0000 (---------------) + I pilot 0x002416c5, // n0x0650 c0x0000 (---------------) + I press 0x002dabca, // n0x0651 c0x0000 (---------------) + I production 0x00315fca, // n0x0652 c0x0000 (---------------) + I recreation 0x00225087, // n0x0653 c0x0000 (---------------) + I repbody 0x0021c703, // n0x0654 c0x0000 (---------------) + I res 0x00298048, // n0x0655 c0x0000 (---------------) + I research 0x002c8a4a, // n0x0656 c0x0000 (---------------) + I rotorcraft 0x00397c86, // n0x0657 c0x0000 (---------------) + I safety 0x0023c949, // n0x0658 c0x0000 (---------------) + I scientist 0x00201248, // n0x0659 c0x0000 (---------------) + I services 0x002aadc4, // n0x065a c0x0000 (---------------) + I show 0x0025de09, // n0x065b c0x0000 (---------------) + I skydiving 0x002b2e48, // n0x065c c0x0000 (---------------) + I software 0x002a4f47, // n0x065d c0x0000 (---------------) + I student 0x0025e586, // n0x065e c0x0000 (---------------) + I trader 0x0029de47, // n0x065f c0x0000 (---------------) + I trading 0x00291747, // n0x0660 c0x0000 (---------------) + I trainer 0x0023de85, // n0x0661 c0x0000 (---------------) + I union 0x002d384c, // n0x0662 c0x0000 (---------------) + I workinggroup 0x00382645, // n0x0663 c0x0000 (---------------) + I works 0x0022d0c3, // n0x0664 c0x0000 (---------------) + I com 0x002325c3, // n0x0665 c0x0000 (---------------) + I edu 0x00264783, // n0x0666 c0x0000 (---------------) + I gov 0x0021e283, // n0x0667 c0x0000 (---------------) + I net 0x00223a43, // n0x0668 c0x0000 (---------------) + I org 0x00203dc2, // n0x0669 c0x0000 (---------------) + I co 0x0022d0c3, // n0x066a c0x0000 (---------------) + I com 0x0021e283, // n0x066b c0x0000 (---------------) + I net 0x0020f543, // n0x066c c0x0000 (---------------) + I nom 0x00223a43, // n0x066d c0x0000 (---------------) + I org 0x0022d0c3, // n0x066e c0x0000 (---------------) + I com 0x0021e283, // n0x066f c0x0000 (---------------) + I net 0x00203e03, // n0x0670 c0x0000 (---------------) + I off 0x00223a43, // n0x0671 c0x0000 (---------------) + I org 0x000f4e08, // n0x0672 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x0673 c0x0000 (---------------) + I com 0x002325c3, // n0x0674 c0x0000 (---------------) + I edu 0x00264783, // n0x0675 c0x0000 (---------------) + I gov 0x00214d03, // n0x0676 c0x0000 (---------------) + I mil 0x0021e283, // n0x0677 c0x0000 (---------------) + I net 0x00223a43, // n0x0678 c0x0000 (---------------) + I org 0x000f4e08, // n0x0679 c0x0000 (---------------) + blogspot 0x00203dc2, // n0x067a c0x0000 (---------------) + I co 0x002003c2, // n0x067b c0x0000 (---------------) + I ed 0x00231ac2, // n0x067c c0x0000 (---------------) + I gv 0x00202742, // n0x067d c0x0000 (---------------) + I it 0x00200882, // n0x067e c0x0000 (---------------) + I og 0x00225102, // n0x067f c0x0000 (---------------) + I pb 0x0462d0c3, // n0x0680 c0x0011 (n0x0689-n0x068a) + I com 0x002325c3, // n0x0681 c0x0000 (---------------) + I edu 0x00210ec3, // n0x0682 c0x0000 (---------------) + I gob 0x00264783, // n0x0683 c0x0000 (---------------) + I gov 0x00267a43, // n0x0684 c0x0000 (---------------) + I int 0x00214d03, // n0x0685 c0x0000 (---------------) + I mil 0x0021e283, // n0x0686 c0x0000 (---------------) + I net 0x00223a43, // n0x0687 c0x0000 (---------------) + I org 0x00233743, // n0x0688 c0x0000 (---------------) + I tur 0x000f4e08, // n0x0689 c0x0000 (---------------) + blogspot 0x0023a704, // n0x068a c0x0000 (---------------) + I e164 0x0033a087, // n0x068b c0x0000 (---------------) + I in-addr 0x00223f03, // n0x068c c0x0000 (---------------) + I ip6 0x0028ba84, // n0x068d c0x0000 (---------------) + I iris 0x0020b143, // n0x068e c0x0000 (---------------) + I uri 0x00277303, // n0x068f c0x0000 (---------------) + I urn 0x00264783, // n0x0690 c0x0000 (---------------) + I gov 0x00203982, // n0x0691 c0x0000 (---------------) + I ac 0x00125b83, // n0x0692 c0x0000 (---------------) + biz 0x05603dc2, // n0x0693 c0x0015 (n0x0698-n0x0699) + I co 0x00231ac2, // n0x0694 c0x0000 (---------------) + I gv 0x001a4f84, // n0x0695 c0x0000 (---------------) + info 0x00200282, // n0x0696 c0x0000 (---------------) + I or 0x000da7c4, // n0x0697 c0x0000 (---------------) + priv 0x000f4e08, // n0x0698 c0x0000 (---------------) + blogspot 0x00231e43, // n0x0699 c0x0000 (---------------) + I act 0x0024ee43, // n0x069a c0x0000 (---------------) + I asn 0x05e2d0c3, // n0x069b c0x0017 (n0x06ab-n0x06ac) + I com 0x00230a84, // n0x069c c0x0000 (---------------) + I conf 0x062325c3, // n0x069d c0x0018 (n0x06ac-n0x06b4) + I edu 0x06664783, // n0x069e c0x0019 (n0x06b4-n0x06b9) + I gov 0x00203782, // n0x069f c0x0000 (---------------) + I id 0x003a4f84, // n0x06a0 c0x0000 (---------------) + I info 0x0021e283, // n0x06a1 c0x0000 (---------------) + I net 0x002e44c3, // n0x06a2 c0x0000 (---------------) + I nsw 0x00204982, // n0x06a3 c0x0000 (---------------) + I nt 0x00223a43, // n0x06a4 c0x0000 (---------------) + I org 0x0021a982, // n0x06a5 c0x0000 (---------------) + I oz 0x002df243, // n0x06a6 c0x0000 (---------------) + I qld 0x00200642, // n0x06a7 c0x0000 (---------------) + I sa 0x00202783, // n0x06a8 c0x0000 (---------------) + I tas 0x00201303, // n0x06a9 c0x0000 (---------------) + I vic 0x00200d02, // n0x06aa c0x0000 (---------------) + I wa 0x000f4e08, // n0x06ab c0x0000 (---------------) + blogspot 0x00231e43, // n0x06ac c0x0000 (---------------) + I act 0x002e44c3, // n0x06ad c0x0000 (---------------) + I nsw 0x00204982, // n0x06ae c0x0000 (---------------) + I nt 0x002df243, // n0x06af c0x0000 (---------------) + I qld 0x00200642, // n0x06b0 c0x0000 (---------------) + I sa 0x00202783, // n0x06b1 c0x0000 (---------------) + I tas 0x00201303, // n0x06b2 c0x0000 (---------------) + I vic 0x00200d02, // n0x06b3 c0x0000 (---------------) + I wa 0x002df243, // n0x06b4 c0x0000 (---------------) + I qld 0x00200642, // n0x06b5 c0x0000 (---------------) + I sa 0x00202783, // n0x06b6 c0x0000 (---------------) + I tas 0x00201303, // n0x06b7 c0x0000 (---------------) + I vic 0x00200d02, // n0x06b8 c0x0000 (---------------) + I wa 0x0022d0c3, // n0x06b9 c0x0000 (---------------) + I com 0x00325b83, // n0x06ba c0x0000 (---------------) + I biz 0x0022d0c3, // n0x06bb c0x0000 (---------------) + I com 0x002325c3, // n0x06bc c0x0000 (---------------) + I edu 0x00264783, // n0x06bd c0x0000 (---------------) + I gov 0x003a4f84, // n0x06be c0x0000 (---------------) + I info 0x00267a43, // n0x06bf c0x0000 (---------------) + I int 0x00214d03, // n0x06c0 c0x0000 (---------------) + I mil 0x0020ff84, // n0x06c1 c0x0000 (---------------) + I name 0x0021e283, // n0x06c2 c0x0000 (---------------) + I net 0x00223a43, // n0x06c3 c0x0000 (---------------) + I org 0x00203902, // n0x06c4 c0x0000 (---------------) + I pp 0x00220443, // n0x06c5 c0x0000 (---------------) + I pro 0x000f4e08, // n0x06c6 c0x0000 (---------------) + blogspot 0x00203dc2, // n0x06c7 c0x0000 (---------------) + I co 0x0022d0c3, // n0x06c8 c0x0000 (---------------) + I com 0x002325c3, // n0x06c9 c0x0000 (---------------) + I edu 0x00264783, // n0x06ca c0x0000 (---------------) + I gov 0x00214d03, // n0x06cb c0x0000 (---------------) + I mil 0x0021e283, // n0x06cc c0x0000 (---------------) + I net 0x00223a43, // n0x06cd c0x0000 (---------------) + I org 0x00206e82, // n0x06ce c0x0000 (---------------) + I rs 0x002726c4, // n0x06cf c0x0000 (---------------) + I unbi 0x002062c4, // n0x06d0 c0x0000 (---------------) + I unsa 0x00325b83, // n0x06d1 c0x0000 (---------------) + I biz 0x00203dc2, // n0x06d2 c0x0000 (---------------) + I co 0x0022d0c3, // n0x06d3 c0x0000 (---------------) + I com 0x002325c3, // n0x06d4 c0x0000 (---------------) + I edu 0x00264783, // n0x06d5 c0x0000 (---------------) + I gov 0x003a4f84, // n0x06d6 c0x0000 (---------------) + I info 0x0021e283, // n0x06d7 c0x0000 (---------------) + I net 0x00223a43, // n0x06d8 c0x0000 (---------------) + I org 0x003758c5, // n0x06d9 c0x0000 (---------------) + I store 0x0020da42, // n0x06da c0x0000 (---------------) + I tv 0x00203982, // n0x06db c0x0000 (---------------) + I ac 0x000f4e08, // n0x06dc c0x0000 (---------------) + blogspot 0x00264783, // n0x06dd c0x0000 (---------------) + I gov 0x00274101, // n0x06de c0x0000 (---------------) + I 0 0x00226901, // n0x06df c0x0000 (---------------) + I 1 0x00237901, // n0x06e0 c0x0000 (---------------) + I 2 0x00226681, // n0x06e1 c0x0000 (---------------) + I 3 0x00232101, // n0x06e2 c0x0000 (---------------) + I 4 0x0026c401, // n0x06e3 c0x0000 (---------------) + I 5 0x00223f81, // n0x06e4 c0x0000 (---------------) + I 6 0x002365c1, // n0x06e5 c0x0000 (---------------) + I 7 0x002e6b41, // n0x06e6 c0x0000 (---------------) + I 8 0x002f7281, // n0x06e7 c0x0000 (---------------) + I 9 0x00200101, // n0x06e8 c0x0000 (---------------) + I a 0x00200001, // n0x06e9 c0x0000 (---------------) + I b 0x000f4e08, // n0x06ea c0x0000 (---------------) + blogspot 0x00200301, // n0x06eb c0x0000 (---------------) + I c 0x00200401, // n0x06ec c0x0000 (---------------) + I d 0x00200081, // n0x06ed c0x0000 (---------------) + I e 0x00200381, // n0x06ee c0x0000 (---------------) + I f 0x00200701, // n0x06ef c0x0000 (---------------) + I g 0x00200601, // n0x06f0 c0x0000 (---------------) + I h 0x00200041, // n0x06f1 c0x0000 (---------------) + I i 0x002014c1, // n0x06f2 c0x0000 (---------------) + I j 0x00200c01, // n0x06f3 c0x0000 (---------------) + I k 0x00200201, // n0x06f4 c0x0000 (---------------) + I l 0x00200181, // n0x06f5 c0x0000 (---------------) + I m 0x002005c1, // n0x06f6 c0x0000 (---------------) + I n 0x00200281, // n0x06f7 c0x0000 (---------------) + I o 0x00200981, // n0x06f8 c0x0000 (---------------) + I p 0x00200a41, // n0x06f9 c0x0000 (---------------) + I q 0x002002c1, // n0x06fa c0x0000 (---------------) + I r 0x00200641, // n0x06fb c0x0000 (---------------) + I s 0x00200141, // n0x06fc c0x0000 (---------------) + I t 0x00200a81, // n0x06fd c0x0000 (---------------) + I u 0x002000c1, // n0x06fe c0x0000 (---------------) + I v 0x00200d01, // n0x06ff c0x0000 (---------------) + I w 0x002045c1, // n0x0700 c0x0000 (---------------) + I x 0x002010c1, // n0x0701 c0x0000 (---------------) + I y 0x00204441, // n0x0702 c0x0000 (---------------) + I z 0x0022d0c3, // n0x0703 c0x0000 (---------------) + I com 0x002325c3, // n0x0704 c0x0000 (---------------) + I edu 0x00264783, // n0x0705 c0x0000 (---------------) + I gov 0x0021e283, // n0x0706 c0x0000 (---------------) + I net 0x00223a43, // n0x0707 c0x0000 (---------------) + I org 0x00203dc2, // n0x0708 c0x0000 (---------------) + I co 0x0022d0c3, // n0x0709 c0x0000 (---------------) + I com 0x002325c3, // n0x070a c0x0000 (---------------) + I edu 0x00200282, // n0x070b c0x0000 (---------------) + I or 0x00223a43, // n0x070c c0x0000 (---------------) + I org 0x00101c07, // n0x070d c0x0000 (---------------) + dscloud 0x00020b06, // n0x070e c0x0000 (---------------) + dyndns 0x0004fd0a, // n0x070f c0x0000 (---------------) + for-better 0x00082788, // n0x0710 c0x0000 (---------------) + for-more 0x00050308, // n0x0711 c0x0000 (---------------) + for-some 0x00050d47, // n0x0712 c0x0000 (---------------) + for-the 0x000636c6, // n0x0713 c0x0000 (---------------) + selfip 0x001374c6, // n0x0714 c0x0000 (---------------) + webhop 0x002c7fc4, // n0x0715 c0x0000 (---------------) + I asso 0x003134c7, // n0x0716 c0x0000 (---------------) + I barreau 0x000f4e08, // n0x0717 c0x0000 (---------------) + blogspot 0x0034ec04, // n0x0718 c0x0000 (---------------) + I gouv 0x0022d0c3, // n0x0719 c0x0000 (---------------) + I com 0x002325c3, // n0x071a c0x0000 (---------------) + I edu 0x00264783, // n0x071b c0x0000 (---------------) + I gov 0x0021e283, // n0x071c c0x0000 (---------------) + I net 0x00223a43, // n0x071d c0x0000 (---------------) + I org 0x0022d0c3, // n0x071e c0x0000 (---------------) + I com 0x002325c3, // n0x071f c0x0000 (---------------) + I edu 0x00210ec3, // n0x0720 c0x0000 (---------------) + I gob 0x00264783, // n0x0721 c0x0000 (---------------) + I gov 0x00267a43, // n0x0722 c0x0000 (---------------) + I int 0x00214d03, // n0x0723 c0x0000 (---------------) + I mil 0x0021e283, // n0x0724 c0x0000 (---------------) + I net 0x00223a43, // n0x0725 c0x0000 (---------------) + I org 0x0020da42, // n0x0726 c0x0000 (---------------) + I tv 0x002be683, // n0x0727 c0x0000 (---------------) + I adm 0x0021a0c3, // n0x0728 c0x0000 (---------------) + I adv 0x0024a5c3, // n0x0729 c0x0000 (---------------) + I agr 0x00201682, // n0x072a c0x0000 (---------------) + I am 0x00247d83, // n0x072b c0x0000 (---------------) + I arq 0x00203b03, // n0x072c c0x0000 (---------------) + I art 0x00206cc3, // n0x072d c0x0000 (---------------) + I ato 0x00200001, // n0x072e c0x0000 (---------------) + I b 0x00204e03, // n0x072f c0x0000 (---------------) + I bio 0x00225384, // n0x0730 c0x0000 (---------------) + I blog 0x002d43c3, // n0x0731 c0x0000 (---------------) + I bmd 0x00302703, // n0x0732 c0x0000 (---------------) + I cim 0x00219ec3, // n0x0733 c0x0000 (---------------) + I cng 0x003998c3, // n0x0734 c0x0000 (---------------) + I cnt 0x0a22d0c3, // n0x0735 c0x0028 (n0x076d-n0x076e) + I com 0x00235044, // n0x0736 c0x0000 (---------------) + I coop 0x00219e83, // n0x0737 c0x0000 (---------------) + I ecn 0x00203d83, // n0x0738 c0x0000 (---------------) + I eco 0x002325c3, // n0x0739 c0x0000 (---------------) + I edu 0x00232303, // n0x073a c0x0000 (---------------) + I emp 0x00203603, // n0x073b c0x0000 (---------------) + I eng 0x002944c3, // n0x073c c0x0000 (---------------) + I esp 0x00302683, // n0x073d c0x0000 (---------------) + I etc 0x00222503, // n0x073e c0x0000 (---------------) + I eti 0x00211903, // n0x073f c0x0000 (---------------) + I far 0x0024b8c4, // n0x0740 c0x0000 (---------------) + I flog 0x0022c142, // n0x0741 c0x0000 (---------------) + I fm 0x0024f683, // n0x0742 c0x0000 (---------------) + I fnd 0x00255743, // n0x0743 c0x0000 (---------------) + I fot 0x00270883, // n0x0744 c0x0000 (---------------) + I fst 0x0033a943, // n0x0745 c0x0000 (---------------) + I g12 0x00338bc3, // n0x0746 c0x0000 (---------------) + I ggf 0x00264783, // n0x0747 c0x0000 (---------------) + I gov 0x002bf643, // n0x0748 c0x0000 (---------------) + I imb 0x0021c903, // n0x0749 c0x0000 (---------------) + I ind 0x003a4dc3, // n0x074a c0x0000 (---------------) + I inf 0x00215283, // n0x074b c0x0000 (---------------) + I jor 0x002e7dc3, // n0x074c c0x0000 (---------------) + I jus 0x0021e643, // n0x074d c0x0000 (---------------) + I leg 0x002b9e43, // n0x074e c0x0000 (---------------) + I lel 0x0021c483, // n0x074f c0x0000 (---------------) + I mat 0x00220d43, // n0x0750 c0x0000 (---------------) + I med 0x00214d03, // n0x0751 c0x0000 (---------------) + I mil 0x00226cc2, // n0x0752 c0x0000 (---------------) + I mp 0x002769c3, // n0x0753 c0x0000 (---------------) + I mus 0x0021e283, // n0x0754 c0x0000 (---------------) + I net 0x0160f543, // n0x0755 c0x0005 (---------------)* o I nom 0x00241c83, // n0x0756 c0x0000 (---------------) + I not 0x002332c3, // n0x0757 c0x0000 (---------------) + I ntr 0x0020cd83, // n0x0758 c0x0000 (---------------) + I odo 0x00223a43, // n0x0759 c0x0000 (---------------) + I org 0x0026b8c3, // n0x075a c0x0000 (---------------) + I ppg 0x00220443, // n0x075b c0x0000 (---------------) + I pro 0x0034ddc3, // n0x075c c0x0000 (---------------) + I psc 0x002ed003, // n0x075d c0x0000 (---------------) + I psi 0x002df403, // n0x075e c0x0000 (---------------) + I qsl 0x00245c05, // n0x075f c0x0000 (---------------) + I radio 0x00226e03, // n0x0760 c0x0000 (---------------) + I rec 0x002df443, // n0x0761 c0x0000 (---------------) + I slg 0x00353ac3, // n0x0762 c0x0000 (---------------) + I srv 0x00222e84, // n0x0763 c0x0000 (---------------) + I taxi 0x0032b043, // n0x0764 c0x0000 (---------------) + I teo 0x0023b743, // n0x0765 c0x0000 (---------------) + I tmp 0x002c9803, // n0x0766 c0x0000 (---------------) + I trd 0x00233743, // n0x0767 c0x0000 (---------------) + I tur 0x0020da42, // n0x0768 c0x0000 (---------------) + I tv 0x0023a8c3, // n0x0769 c0x0000 (---------------) + I vet 0x002f0384, // n0x076a c0x0000 (---------------) + I vlog 0x0032c3c4, // n0x076b c0x0000 (---------------) + I wiki 0x002418c3, // n0x076c c0x0000 (---------------) + I zlg 0x000f4e08, // n0x076d c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x076e c0x0000 (---------------) + I com 0x002325c3, // n0x076f c0x0000 (---------------) + I edu 0x00264783, // n0x0770 c0x0000 (---------------) + I gov 0x0021e283, // n0x0771 c0x0000 (---------------) + I net 0x00223a43, // n0x0772 c0x0000 (---------------) + I org 0x0022d0c3, // n0x0773 c0x0000 (---------------) + I com 0x002325c3, // n0x0774 c0x0000 (---------------) + I edu 0x00264783, // n0x0775 c0x0000 (---------------) + I gov 0x0021e283, // n0x0776 c0x0000 (---------------) + I net 0x00223a43, // n0x0777 c0x0000 (---------------) + I org 0x00203dc2, // n0x0778 c0x0000 (---------------) + I co 0x00223a43, // n0x0779 c0x0000 (---------------) + I org 0x0b62d0c3, // n0x077a c0x002d (n0x077e-n0x077f) + I com 0x00264783, // n0x077b c0x0000 (---------------) + I gov 0x00214d03, // n0x077c c0x0000 (---------------) + I mil 0x00203e02, // n0x077d c0x0000 (---------------) + I of 0x000f4e08, // n0x077e c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x077f c0x0000 (---------------) + I com 0x002325c3, // n0x0780 c0x0000 (---------------) + I edu 0x00264783, // n0x0781 c0x0000 (---------------) + I gov 0x0021e283, // n0x0782 c0x0000 (---------------) + I net 0x00223a43, // n0x0783 c0x0000 (---------------) + I org 0x0000a182, // n0x0784 c0x0000 (---------------) + za 0x00201702, // n0x0785 c0x0000 (---------------) + I ab 0x00229342, // n0x0786 c0x0000 (---------------) + I bc 0x000f4e08, // n0x0787 c0x0000 (---------------) + blogspot 0x00003dc2, // n0x0788 c0x0000 (---------------) + co 0x00234242, // n0x0789 c0x0000 (---------------) + I gc 0x0020a382, // n0x078a c0x0000 (---------------) + I mb 0x0020d0c2, // n0x078b c0x0000 (---------------) + I nb 0x00230b02, // n0x078c c0x0000 (---------------) + I nf 0x00203842, // n0x078d c0x0000 (---------------) + I nl 0x00206302, // n0x078e c0x0000 (---------------) + I ns 0x00204982, // n0x078f c0x0000 (---------------) + I nt 0x002020c2, // n0x0790 c0x0000 (---------------) + I nu 0x00200582, // n0x0791 c0x0000 (---------------) + I on 0x002087c2, // n0x0792 c0x0000 (---------------) + I pe 0x00375542, // n0x0793 c0x0000 (---------------) + I qc 0x00208882, // n0x0794 c0x0000 (---------------) + I sk 0x002617c2, // n0x0795 c0x0000 (---------------) + I yk 0x00141f09, // n0x0796 c0x0000 (---------------) + ftpaccess 0x0016e40b, // n0x0797 c0x0000 (---------------) + game-server 0x000cb588, // n0x0798 c0x0000 (---------------) + myphotos 0x0003f989, // n0x0799 c0x0000 (---------------) + scrapping 0x00264783, // n0x079a c0x0000 (---------------) + I gov 0x000f4e08, // n0x079b c0x0000 (---------------) + blogspot 0x000f4e08, // n0x079c c0x0000 (---------------) + blogspot 0x00203982, // n0x079d c0x0000 (---------------) + I ac 0x002c7fc4, // n0x079e c0x0000 (---------------) + I asso 0x00203dc2, // n0x079f c0x0000 (---------------) + I co 0x0022d0c3, // n0x07a0 c0x0000 (---------------) + I com 0x002003c2, // n0x07a1 c0x0000 (---------------) + I ed 0x002325c3, // n0x07a2 c0x0000 (---------------) + I edu 0x00200702, // n0x07a3 c0x0000 (---------------) + I go 0x0034ec04, // n0x07a4 c0x0000 (---------------) + I gouv 0x00267a43, // n0x07a5 c0x0000 (---------------) + I int 0x00246c82, // n0x07a6 c0x0000 (---------------) + I md 0x0021e283, // n0x07a7 c0x0000 (---------------) + I net 0x00200282, // n0x07a8 c0x0000 (---------------) + I or 0x00223a43, // n0x07a9 c0x0000 (---------------) + I org 0x002416c6, // n0x07aa c0x0000 (---------------) + I presse 0x00306f4f, // n0x07ab c0x0000 (---------------) + I xn--aroport-bya 0x006f6783, // n0x07ac c0x0001 (---------------) ! I www 0x000f4e08, // n0x07ad c0x0000 (---------------) + blogspot 0x00203dc2, // n0x07ae c0x0000 (---------------) + I co 0x00210ec3, // n0x07af c0x0000 (---------------) + I gob 0x00264783, // n0x07b0 c0x0000 (---------------) + I gov 0x00214d03, // n0x07b1 c0x0000 (---------------) + I mil 0x00203dc2, // n0x07b2 c0x0000 (---------------) + I co 0x0022d0c3, // n0x07b3 c0x0000 (---------------) + I com 0x00264783, // n0x07b4 c0x0000 (---------------) + I gov 0x0021e283, // n0x07b5 c0x0000 (---------------) + I net 0x00203982, // n0x07b6 c0x0000 (---------------) + I ac 0x00209982, // n0x07b7 c0x0000 (---------------) + I ah 0x0e6eae09, // n0x07b8 c0x0039 (n0x07e3-n0x07e4) o I amazonaws 0x00207642, // n0x07b9 c0x0000 (---------------) + I bj 0x0ee2d0c3, // n0x07ba c0x003b (n0x07e5-n0x07e6) + I com 0x0023d182, // n0x07bb c0x0000 (---------------) + I cq 0x002325c3, // n0x07bc c0x0000 (---------------) + I edu 0x00215242, // n0x07bd c0x0000 (---------------) + I fj 0x00221d82, // n0x07be c0x0000 (---------------) + I gd 0x00264783, // n0x07bf c0x0000 (---------------) + I gov 0x0028fbc2, // n0x07c0 c0x0000 (---------------) + I gs 0x002f6f82, // n0x07c1 c0x0000 (---------------) + I gx 0x00359ec2, // n0x07c2 c0x0000 (---------------) + I gz 0x00202f42, // n0x07c3 c0x0000 (---------------) + I ha 0x00285f82, // n0x07c4 c0x0000 (---------------) + I hb 0x00208402, // n0x07c5 c0x0000 (---------------) + I he 0x002009c2, // n0x07c6 c0x0000 (---------------) + I hi 0x0020f882, // n0x07c7 c0x0000 (---------------) + I hk 0x0024e142, // n0x07c8 c0x0000 (---------------) + I hl 0x002168c2, // n0x07c9 c0x0000 (---------------) + I hn 0x002a6e02, // n0x07ca c0x0000 (---------------) + I jl 0x0022b142, // n0x07cb c0x0000 (---------------) + I js 0x00231f02, // n0x07cc c0x0000 (---------------) + I jx 0x00224942, // n0x07cd c0x0000 (---------------) + I ln 0x00214d03, // n0x07ce c0x0000 (---------------) + I mil 0x00207c82, // n0x07cf c0x0000 (---------------) + I mo 0x0021e283, // n0x07d0 c0x0000 (---------------) + I net 0x002354c2, // n0x07d1 c0x0000 (---------------) + I nm 0x002623c2, // n0x07d2 c0x0000 (---------------) + I nx 0x00223a43, // n0x07d3 c0x0000 (---------------) + I org 0x00247e02, // n0x07d4 c0x0000 (---------------) + I qh 0x00213402, // n0x07d5 c0x0000 (---------------) + I sc 0x00256cc2, // n0x07d6 c0x0000 (---------------) + I sd 0x00202802, // n0x07d7 c0x0000 (---------------) + I sh 0x0020ce82, // n0x07d8 c0x0000 (---------------) + I sn 0x002e6902, // n0x07d9 c0x0000 (---------------) + I sx 0x00231ec2, // n0x07da c0x0000 (---------------) + I tj 0x00242e02, // n0x07db c0x0000 (---------------) + I tw 0x002b0b82, // n0x07dc c0x0000 (---------------) + I xj 0x002f8f8a, // n0x07dd c0x0000 (---------------) + I xn--55qx5d 0x0033fc0a, // n0x07de c0x0000 (---------------) + I xn--io0a7i 0x003700ca, // n0x07df c0x0000 (---------------) + I xn--od0alg 0x003a5302, // n0x07e0 c0x0000 (---------------) + I xz 0x0021f042, // n0x07e1 c0x0000 (---------------) + I yn 0x00234d82, // n0x07e2 c0x0000 (---------------) + I zj 0x0e82eb87, // n0x07e3 c0x003a (n0x07e4-n0x07e5) + compute 0x0019b70a, // n0x07e4 c0x0000 (---------------) + cn-north-1 0x0f2eae09, // n0x07e5 c0x003c (n0x07e6-n0x07e7) o I amazonaws 0x0f79b70a, // n0x07e6 c0x003d (n0x07e7-n0x07e8) o I cn-north-1 0x00026642, // n0x07e7 c0x0000 (---------------) + s3 0x00244d04, // n0x07e8 c0x0000 (---------------) + I arts 0x0fe2d0c3, // n0x07e9 c0x003f (n0x07f5-n0x07f6) + I com 0x002325c3, // n0x07ea c0x0000 (---------------) + I edu 0x00246bc4, // n0x07eb c0x0000 (---------------) + I firm 0x00264783, // n0x07ec c0x0000 (---------------) + I gov 0x003a4f84, // n0x07ed c0x0000 (---------------) + I info 0x00267a43, // n0x07ee c0x0000 (---------------) + I int 0x00214d03, // n0x07ef c0x0000 (---------------) + I mil 0x0021e283, // n0x07f0 c0x0000 (---------------) + I net 0x0020f543, // n0x07f1 c0x0000 (---------------) + I nom 0x00223a43, // n0x07f2 c0x0000 (---------------) + I org 0x00226e03, // n0x07f3 c0x0000 (---------------) + I rec 0x002292c3, // n0x07f4 c0x0000 (---------------) + I web 0x000f4e08, // n0x07f5 c0x0000 (---------------) + blogspot 0x00119d45, // n0x07f6 c0x0000 (---------------) + 1kapp 0x001014c2, // n0x07f7 c0x0000 (---------------) + 4u 0x00169cc6, // n0x07f8 c0x0000 (---------------) + africa 0x106eae09, // n0x07f9 c0x0041 (n0x08c6-n0x08d8) o I amazonaws 0x00101dc7, // n0x07fa c0x0000 (---------------) + appspot 0x00002942, // n0x07fb c0x0000 (---------------) + ar 0x0019330a, // n0x07fc c0x0000 (---------------) + betainabox 0x00025387, // n0x07fd c0x0000 (---------------) + blogdns 0x000f4e08, // n0x07fe c0x0000 (---------------) + blogspot 0x0001ac42, // n0x07ff c0x0000 (---------------) + br 0x0013cc07, // n0x0800 c0x0000 (---------------) + cechire 0x0017abcf, // n0x0801 c0x0000 (---------------) + cloudcontrolapp 0x000d5e0f, // n0x0802 c0x0000 (---------------) + cloudcontrolled 0x00019ec2, // n0x0803 c0x0000 (---------------) + cn 0x00003dc2, // n0x0804 c0x0000 (---------------) + co 0x00094408, // n0x0805 c0x0000 (---------------) + codespot 0x00000402, // n0x0806 c0x0000 (---------------) + de 0x001480c8, // n0x0807 c0x0000 (---------------) + dnsalias 0x000749c7, // n0x0808 c0x0000 (---------------) + dnsdojo 0x0000cdcb, // n0x0809 c0x0000 (---------------) + doesntexist 0x00165b89, // n0x080a c0x0000 (---------------) + dontexist 0x00147fc7, // n0x080b c0x0000 (---------------) + doomdns 0x000e8b4c, // n0x080c c0x0000 (---------------) + dreamhosters 0x001a2cc7, // n0x080d c0x0000 (---------------) + dsmynas 0x0011eb8a, // n0x080e c0x0000 (---------------) + dyn-o-saur 0x00189b08, // n0x080f c0x0000 (---------------) + dynalias 0x0006cb0e, // n0x0810 c0x0000 (---------------) + dyndns-at-home 0x000d35ce, // n0x0811 c0x0000 (---------------) + dyndns-at-work 0x000251cb, // n0x0812 c0x0000 (---------------) + dyndns-blog 0x000e02cb, // n0x0813 c0x0000 (---------------) + dyndns-free 0x00020b0b, // n0x0814 c0x0000 (---------------) + dyndns-home 0x00023d49, // n0x0815 c0x0000 (---------------) + dyndns-ip 0x00024d0b, // n0x0816 c0x0000 (---------------) + dyndns-mail 0x00028d8d, // n0x0817 c0x0000 (---------------) + dyndns-office 0x00173acb, // n0x0818 c0x0000 (---------------) + dyndns-pics 0x00064bcd, // n0x0819 c0x0000 (---------------) + dyndns-remote 0x0019fc0d, // n0x081a c0x0000 (---------------) + dyndns-server 0x0010b58a, // n0x081b c0x0000 (---------------) + dyndns-web 0x0012c20b, // n0x081c c0x0000 (---------------) + dyndns-wiki 0x0018248b, // n0x081d c0x0000 (---------------) + dyndns-work 0x0001d890, // n0x081e c0x0000 (---------------) + elasticbeanstalk 0x000058cf, // n0x081f c0x0000 (---------------) + est-a-la-maison 0x0013024f, // n0x0820 c0x0000 (---------------) + est-a-la-masion 0x00167bcd, // n0x0821 c0x0000 (---------------) + est-le-patron 0x00077890, // n0x0822 c0x0000 (---------------) + est-mon-blogueur 0x00025c02, // n0x0823 c0x0000 (---------------) + eu 0x001a2b48, // n0x0824 c0x0000 (---------------) + familyds 0x000454cb, // n0x0825 c0x0000 (---------------) + firebaseapp 0x0004d548, // n0x0826 c0x0000 (---------------) + flynnhub 0x0005b107, // n0x0827 c0x0000 (---------------) + from-ak 0x0005b447, // n0x0828 c0x0000 (---------------) + from-al 0x0005b607, // n0x0829 c0x0000 (---------------) + from-ar 0x0005bb87, // n0x082a c0x0000 (---------------) + from-ca 0x0005d447, // n0x082b c0x0000 (---------------) + from-ct 0x0005da47, // n0x082c c0x0000 (---------------) + from-dc 0x0005e1c7, // n0x082d c0x0000 (---------------) + from-de 0x0005e707, // n0x082e c0x0000 (---------------) + from-fl 0x0005f747, // n0x082f c0x0000 (---------------) + from-ga 0x0005fac7, // n0x0830 c0x0000 (---------------) + from-hi 0x00060a07, // n0x0831 c0x0000 (---------------) + from-ia 0x00060bc7, // n0x0832 c0x0000 (---------------) + from-id 0x00060d87, // n0x0833 c0x0000 (---------------) + from-il 0x00060f47, // n0x0834 c0x0000 (---------------) + from-in 0x00061247, // n0x0835 c0x0000 (---------------) + from-ks 0x00061647, // n0x0836 c0x0000 (---------------) + from-ky 0x00062207, // n0x0837 c0x0000 (---------------) + from-ma 0x000626c7, // n0x0838 c0x0000 (---------------) + from-md 0x00062c47, // n0x0839 c0x0000 (---------------) + from-mi 0x000639c7, // n0x083a c0x0000 (---------------) + from-mn 0x00063b87, // n0x083b c0x0000 (---------------) + from-mo 0x00063e87, // n0x083c c0x0000 (---------------) + from-ms 0x00064287, // n0x083d c0x0000 (---------------) + from-mt 0x00064487, // n0x083e c0x0000 (---------------) + from-nc 0x00065287, // n0x083f c0x0000 (---------------) + from-nd 0x00065447, // n0x0840 c0x0000 (---------------) + from-ne 0x00065847, // n0x0841 c0x0000 (---------------) + from-nh 0x00065f87, // n0x0842 c0x0000 (---------------) + from-nj 0x00066487, // n0x0843 c0x0000 (---------------) + from-nm 0x00066b07, // n0x0844 c0x0000 (---------------) + from-nv 0x00067e47, // n0x0845 c0x0000 (---------------) + from-oh 0x00068107, // n0x0846 c0x0000 (---------------) + from-ok 0x00068487, // n0x0847 c0x0000 (---------------) + from-or 0x00068647, // n0x0848 c0x0000 (---------------) + from-pa 0x000689c7, // n0x0849 c0x0000 (---------------) + from-pr 0x00069087, // n0x084a c0x0000 (---------------) + from-ri 0x00069607, // n0x084b c0x0000 (---------------) + from-sc 0x00069a07, // n0x084c c0x0000 (---------------) + from-sd 0x0006be87, // n0x084d c0x0000 (---------------) + from-tn 0x0006c047, // n0x084e c0x0000 (---------------) + from-tx 0x0006c487, // n0x084f c0x0000 (---------------) + from-ut 0x0006de07, // n0x0850 c0x0000 (---------------) + from-va 0x0006e447, // n0x0851 c0x0000 (---------------) + from-vt 0x0006e747, // n0x0852 c0x0000 (---------------) + from-wa 0x0006e907, // n0x0853 c0x0000 (---------------) + from-wi 0x0006ec87, // n0x0854 c0x0000 (---------------) + from-wv 0x0006f487, // n0x0855 c0x0000 (---------------) + from-wy 0x0000a482, // n0x0856 c0x0000 (---------------) + gb 0x000ce8c7, // n0x0857 c0x0000 (---------------) + getmyip 0x000c5e11, // n0x0858 c0x0000 (---------------) + githubusercontent 0x000d818a, // n0x0859 c0x0000 (---------------) + googleapis 0x0009428a, // n0x085a c0x0000 (---------------) + googlecode 0x00051786, // n0x085b c0x0000 (---------------) + gotdns 0x0001228b, // n0x085c c0x0000 (---------------) + gotpantheon 0x000008c2, // n0x085d c0x0000 (---------------) + gr 0x00095009, // n0x085e c0x0000 (---------------) + herokuapp 0x0008c049, // n0x085f c0x0000 (---------------) + herokussl 0x0000f882, // n0x0860 c0x0000 (---------------) + hk 0x0014904a, // n0x0861 c0x0000 (---------------) + hobby-site 0x0009f749, // n0x0862 c0x0000 (---------------) + homelinux 0x000a0bc8, // n0x0863 c0x0000 (---------------) + homeunix 0x00022f82, // n0x0864 c0x0000 (---------------) + hu 0x00110489, // n0x0865 c0x0000 (---------------) + iamallama 0x0015a6ce, // n0x0866 c0x0000 (---------------) + is-a-anarchist 0x0009f44c, // n0x0867 c0x0000 (---------------) + is-a-blogger 0x000ccfcf, // n0x0868 c0x0000 (---------------) + is-a-bookkeeper 0x0018490e, // n0x0869 c0x0000 (---------------) + is-a-bulls-fan 0x0001044c, // n0x086a c0x0000 (---------------) + is-a-caterer 0x00011709, // n0x086b c0x0000 (---------------) + is-a-chef 0x00015711, // n0x086c c0x0000 (---------------) + is-a-conservative 0x000170c8, // n0x086d c0x0000 (---------------) + is-a-cpa 0x0001f6d2, // n0x086e c0x0000 (---------------) + is-a-cubicle-slave 0x00022b8d, // n0x086f c0x0000 (---------------) + is-a-democrat 0x0002888d, // n0x0870 c0x0000 (---------------) + is-a-designer 0x00075acb, // n0x0871 c0x0000 (---------------) + is-a-doctor 0x00167395, // n0x0872 c0x0000 (---------------) + is-a-financialadvisor 0x00043289, // n0x0873 c0x0000 (---------------) + is-a-geek 0x00047a0a, // n0x0874 c0x0000 (---------------) + is-a-green 0x0004adc9, // n0x0875 c0x0000 (---------------) + is-a-guru 0x00054ed0, // n0x0876 c0x0000 (---------------) + is-a-hard-worker 0x0005d78b, // n0x0877 c0x0000 (---------------) + is-a-hunter 0x0005f28f, // n0x0878 c0x0000 (---------------) + is-a-landscaper 0x0006684b, // n0x0879 c0x0000 (---------------) + is-a-lawyer 0x00068d8c, // n0x087a c0x0000 (---------------) + is-a-liberal 0x00069210, // n0x087b c0x0000 (---------------) + is-a-libertarian 0x00075f0a, // n0x087c c0x0000 (---------------) + is-a-llama 0x0007688d, // n0x087d c0x0000 (---------------) + is-a-musician 0x0007c98e, // n0x087e c0x0000 (---------------) + is-a-nascarfan 0x0008374a, // n0x087f c0x0000 (---------------) + is-a-nurse 0x0013238c, // n0x0880 c0x0000 (---------------) + is-a-painter 0x00091414, // n0x0881 c0x0000 (---------------) + is-a-personaltrainer 0x00094c91, // n0x0882 c0x0000 (---------------) + is-a-photographer 0x0009530b, // n0x0883 c0x0000 (---------------) + is-a-player 0x00097bcf, // n0x0884 c0x0000 (---------------) + is-a-republican 0x0009ad0d, // n0x0885 c0x0000 (---------------) + is-a-rockstar 0x0009edce, // n0x0886 c0x0000 (---------------) + is-a-socialist 0x000a4e0c, // n0x0887 c0x0000 (---------------) + is-a-student 0x000a54cc, // n0x0888 c0x0000 (---------------) + is-a-teacher 0x000a600b, // n0x0889 c0x0000 (---------------) + is-a-techie 0x000a630e, // n0x088a c0x0000 (---------------) + is-a-therapist 0x000b5f90, // n0x088b c0x0000 (---------------) + is-an-accountant 0x0014a0cb, // n0x088c c0x0000 (---------------) + is-an-actor 0x000ed70d, // n0x088d c0x0000 (---------------) + is-an-actress 0x00153d8f, // n0x088e c0x0000 (---------------) + is-an-anarchist 0x000fac8c, // n0x088f c0x0000 (---------------) + is-an-artist 0x00164b4e, // n0x0890 c0x0000 (---------------) + is-an-engineer 0x000a9ad1, // n0x0891 c0x0000 (---------------) + is-an-entertainer 0x000b350c, // n0x0892 c0x0000 (---------------) + is-certified 0x000b4847, // n0x0893 c0x0000 (---------------) + is-gone 0x000b59cd, // n0x0894 c0x0000 (---------------) + is-into-anime 0x000d260c, // n0x0895 c0x0000 (---------------) + is-into-cars 0x00112a10, // n0x0896 c0x0000 (---------------) + is-into-cartoons 0x0014428d, // n0x0897 c0x0000 (---------------) + is-into-games 0x000c9687, // n0x0898 c0x0000 (---------------) + is-leet 0x00157490, // n0x0899 c0x0000 (---------------) + is-not-certified 0x000e1c48, // n0x089a c0x0000 (---------------) + is-slick 0x000e2e4b, // n0x089b c0x0000 (---------------) + is-uberleet 0x00147c4f, // n0x089c c0x0000 (---------------) + is-with-theband 0x000fdf48, // n0x089d c0x0000 (---------------) + isa-geek 0x000d838d, // n0x089e c0x0000 (---------------) + isa-hockeynut 0x00163c90, // n0x089f c0x0000 (---------------) + issmarterthanyou 0x000a8c83, // n0x08a0 c0x0000 (---------------) + jpn 0x00007b42, // n0x08a1 c0x0000 (---------------) + kr 0x00052289, // n0x08a2 c0x0000 (---------------) + likes-pie 0x0006c90a, // n0x08a3 c0x0000 (---------------) + likescandy 0x00010003, // n0x08a4 c0x0000 (---------------) + mex 0x00110bc8, // n0x08a5 c0x0000 (---------------) + neat-url 0x0019c347, // n0x08a6 c0x0000 (---------------) + nfshost 0x00000842, // n0x08a7 c0x0000 (---------------) + no 0x00045d8a, // n0x08a8 c0x0000 (---------------) + operaunite 0x0017a94f, // n0x08a9 c0x0000 (---------------) + outsystemscloud 0x0013760c, // n0x08aa c0x0000 (---------------) + pagefrontapp 0x001378d2, // n0x08ab c0x0000 (---------------) + pagespeedmobilizer 0x0010da43, // n0x08ac c0x0000 (---------------) + qa2 0x00175542, // n0x08ad c0x0000 (---------------) + qc 0x001388c8, // n0x08ae c0x0000 (---------------) + rackmaze 0x000d5d87, // n0x08af c0x0000 (---------------) + rhcloud 0x00000f82, // n0x08b0 c0x0000 (---------------) + ro 0x0000efc2, // n0x08b1 c0x0000 (---------------) + ru 0x00000642, // n0x08b2 c0x0000 (---------------) + sa 0x00133710, // n0x08b3 c0x0000 (---------------) + saves-the-whales 0x00001242, // n0x08b4 c0x0000 (---------------) + se 0x000636c6, // n0x08b5 c0x0000 (---------------) + selfip 0x00040ace, // n0x08b6 c0x0000 (---------------) + sells-for-less 0x00085b0b, // n0x08b7 c0x0000 (---------------) + sells-for-u 0x000c7008, // n0x08b8 c0x0000 (---------------) + servebbs 0x000c44ca, // n0x08b9 c0x0000 (---------------) + simple-url 0x000ed047, // n0x08ba c0x0000 (---------------) + sinaapp 0x000046cd, // n0x08bb c0x0000 (---------------) + space-to-rent 0x000ffdcc, // n0x08bc c0x0000 (---------------) + teaches-yoga 0x00000bc2, // n0x08bd c0x0000 (---------------) + uk 0x00001102, // n0x08be c0x0000 (---------------) + us 0x00002102, // n0x08bf c0x0000 (---------------) + uy 0x000ecf8a, // n0x08c0 c0x0000 (---------------) + vipsinaapp 0x000d808a, // n0x08c1 c0x0000 (---------------) + withgoogle 0x000dddcb, // n0x08c2 c0x0000 (---------------) + withyoutube 0x000f4b8e, // n0x08c3 c0x0000 (---------------) + writesthisblog 0x000d0f08, // n0x08c4 c0x0000 (---------------) + yolasite 0x0000a182, // n0x08c5 c0x0000 (---------------) + za 0x1082eb87, // n0x08c6 c0x0042 (n0x08d8-n0x08e1) + compute 0x10c2eb89, // n0x08c7 c0x0043 (n0x08e1-n0x08e3) + compute-1 0x0000d643, // n0x08c8 c0x0000 (---------------) + elb 0x1126bb8c, // n0x08c9 c0x0044 (n0x08e3-n0x08e4) o I eu-central-1 0x00026642, // n0x08ca c0x0000 (---------------) + s3 0x0011a8d1, // n0x08cb c0x0000 (---------------) + s3-ap-northeast-1 0x00126cd1, // n0x08cc c0x0000 (---------------) + s3-ap-southeast-1 0x0004f251, // n0x08cd c0x0000 (---------------) + s3-ap-southeast-2 0x0006bacf, // n0x08ce c0x0000 (---------------) + s3-eu-central-1 0x00195bcc, // n0x08cf c0x0000 (---------------) + s3-eu-west-1 0x000d620d, // n0x08d0 c0x0000 (---------------) + s3-external-1 0x00104c4d, // n0x08d1 c0x0000 (---------------) + s3-external-2 0x00109c95, // n0x08d2 c0x0000 (---------------) + s3-fips-us-gov-west-1 0x0011ef4c, // n0x08d3 c0x0000 (---------------) + s3-sa-east-1 0x0015c250, // n0x08d4 c0x0000 (---------------) + s3-us-gov-west-1 0x0002664c, // n0x08d5 c0x0000 (---------------) + s3-us-west-1 0x000bc6cc, // n0x08d6 c0x0000 (---------------) + s3-us-west-2 0x0011e1c9, // n0x08d7 c0x0000 (---------------) + us-east-1 0x0011a98e, // n0x08d8 c0x0000 (---------------) + ap-northeast-1 0x00126d8e, // n0x08d9 c0x0000 (---------------) + ap-southeast-1 0x0004f30e, // n0x08da c0x0000 (---------------) + ap-southeast-2 0x0006bb8c, // n0x08db c0x0000 (---------------) + eu-central-1 0x00195c89, // n0x08dc c0x0000 (---------------) + eu-west-1 0x0011f009, // n0x08dd c0x0000 (---------------) + sa-east-1 0x00109e8d, // n0x08de c0x0000 (---------------) + us-gov-west-1 0x00026709, // n0x08df c0x0000 (---------------) + us-west-1 0x000bc789, // n0x08e0 c0x0000 (---------------) + us-west-2 0x00119cc3, // n0x08e1 c0x0000 (---------------) + z-1 0x00056a03, // n0x08e2 c0x0000 (---------------) + z-2 0x00026642, // n0x08e3 c0x0000 (---------------) + s3 0x00203982, // n0x08e4 c0x0000 (---------------) + I ac 0x00203dc2, // n0x08e5 c0x0000 (---------------) + I co 0x002003c2, // n0x08e6 c0x0000 (---------------) + I ed 0x00203a42, // n0x08e7 c0x0000 (---------------) + I fi 0x00200702, // n0x08e8 c0x0000 (---------------) + I go 0x00200282, // n0x08e9 c0x0000 (---------------) + I or 0x00200642, // n0x08ea c0x0000 (---------------) + I sa 0x0022d0c3, // n0x08eb c0x0000 (---------------) + I com 0x002325c3, // n0x08ec c0x0000 (---------------) + I edu 0x00264783, // n0x08ed c0x0000 (---------------) + I gov 0x003a4dc3, // n0x08ee c0x0000 (---------------) + I inf 0x0021e283, // n0x08ef c0x0000 (---------------) + I net 0x00223a43, // n0x08f0 c0x0000 (---------------) + I org 0x000f4e08, // n0x08f1 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x08f2 c0x0000 (---------------) + I com 0x002325c3, // n0x08f3 c0x0000 (---------------) + I edu 0x0021e283, // n0x08f4 c0x0000 (---------------) + I net 0x00223a43, // n0x08f5 c0x0000 (---------------) + I org 0x0004e0c3, // n0x08f6 c0x0000 (---------------) + ath 0x00264783, // n0x08f7 c0x0000 (---------------) + I gov 0x00203982, // n0x08f8 c0x0000 (---------------) + I ac 0x00325b83, // n0x08f9 c0x0000 (---------------) + I biz 0x12e2d0c3, // n0x08fa c0x004b (n0x0905-n0x0906) + I com 0x0027ea87, // n0x08fb c0x0000 (---------------) + I ekloges 0x00264783, // n0x08fc c0x0000 (---------------) + I gov 0x00314403, // n0x08fd c0x0000 (---------------) + I ltd 0x0020ff84, // n0x08fe c0x0000 (---------------) + I name 0x0021e283, // n0x08ff c0x0000 (---------------) + I net 0x00223a43, // n0x0900 c0x0000 (---------------) + I org 0x0026f0ca, // n0x0901 c0x0000 (---------------) + I parliament 0x002416c5, // n0x0902 c0x0000 (---------------) + I press 0x00220443, // n0x0903 c0x0000 (---------------) + I pro 0x00200142, // n0x0904 c0x0000 (---------------) + I tm 0x000f4e08, // n0x0905 c0x0000 (---------------) + blogspot 0x000f4e08, // n0x0906 c0x0000 (---------------) + blogspot 0x000f4e08, // n0x0907 c0x0000 (---------------) + blogspot 0x0002d0c3, // n0x0908 c0x0000 (---------------) + com 0x000edb8f, // n0x0909 c0x0000 (---------------) + fuettertdasnetz 0x00165d0a, // n0x090a c0x0000 (---------------) + isteingeek 0x0009f087, // n0x090b c0x0000 (---------------) + istmein 0x0001e10a, // n0x090c c0x0000 (---------------) + lebtimnetz 0x0008fa4a, // n0x090d c0x0000 (---------------) + leitungsen 0x0012bb8d, // n0x090e c0x0000 (---------------) + traeumtgerade 0x000f4e08, // n0x090f c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x0910 c0x0000 (---------------) + I com 0x002325c3, // n0x0911 c0x0000 (---------------) + I edu 0x00264783, // n0x0912 c0x0000 (---------------) + I gov 0x0021e283, // n0x0913 c0x0000 (---------------) + I net 0x00223a43, // n0x0914 c0x0000 (---------------) + I org 0x00203b03, // n0x0915 c0x0000 (---------------) + I art 0x0022d0c3, // n0x0916 c0x0000 (---------------) + I com 0x002325c3, // n0x0917 c0x0000 (---------------) + I edu 0x00210ec3, // n0x0918 c0x0000 (---------------) + I gob 0x00264783, // n0x0919 c0x0000 (---------------) + I gov 0x00214d03, // n0x091a c0x0000 (---------------) + I mil 0x0021e283, // n0x091b c0x0000 (---------------) + I net 0x00223a43, // n0x091c c0x0000 (---------------) + I org 0x0028c203, // n0x091d c0x0000 (---------------) + I sld 0x002292c3, // n0x091e c0x0000 (---------------) + I web 0x00203b03, // n0x091f c0x0000 (---------------) + I art 0x002c7fc4, // n0x0920 c0x0000 (---------------) + I asso 0x0022d0c3, // n0x0921 c0x0000 (---------------) + I com 0x002325c3, // n0x0922 c0x0000 (---------------) + I edu 0x00264783, // n0x0923 c0x0000 (---------------) + I gov 0x0021e283, // n0x0924 c0x0000 (---------------) + I net 0x00223a43, // n0x0925 c0x0000 (---------------) + I org 0x002200c3, // n0x0926 c0x0000 (---------------) + I pol 0x0022d0c3, // n0x0927 c0x0000 (---------------) + I com 0x002325c3, // n0x0928 c0x0000 (---------------) + I edu 0x00208543, // n0x0929 c0x0000 (---------------) + I fin 0x00210ec3, // n0x092a c0x0000 (---------------) + I gob 0x00264783, // n0x092b c0x0000 (---------------) + I gov 0x003a4f84, // n0x092c c0x0000 (---------------) + I info 0x00369643, // n0x092d c0x0000 (---------------) + I k12 0x00220d43, // n0x092e c0x0000 (---------------) + I med 0x00214d03, // n0x092f c0x0000 (---------------) + I mil 0x0021e283, // n0x0930 c0x0000 (---------------) + I net 0x00223a43, // n0x0931 c0x0000 (---------------) + I org 0x00220443, // n0x0932 c0x0000 (---------------) + I pro 0x003a1e83, // n0x0933 c0x0000 (---------------) + I aip 0x1522d0c3, // n0x0934 c0x0054 (n0x093d-n0x093e) + I com 0x002325c3, // n0x0935 c0x0000 (---------------) + I edu 0x002b3703, // n0x0936 c0x0000 (---------------) + I fie 0x00264783, // n0x0937 c0x0000 (---------------) + I gov 0x00268ec3, // n0x0938 c0x0000 (---------------) + I lib 0x00220d43, // n0x0939 c0x0000 (---------------) + I med 0x00223a43, // n0x093a c0x0000 (---------------) + I org 0x002052c3, // n0x093b c0x0000 (---------------) + I pri 0x00317c84, // n0x093c c0x0000 (---------------) + I riik 0x000f4e08, // n0x093d c0x0000 (---------------) + blogspot 0x15a2d0c3, // n0x093e c0x0056 (n0x0947-n0x0948) + I com 0x002325c3, // n0x093f c0x0000 (---------------) + I edu 0x002a0c83, // n0x0940 c0x0000 (---------------) + I eun 0x00264783, // n0x0941 c0x0000 (---------------) + I gov 0x00214d03, // n0x0942 c0x0000 (---------------) + I mil 0x0020ff84, // n0x0943 c0x0000 (---------------) + I name 0x0021e283, // n0x0944 c0x0000 (---------------) + I net 0x00223a43, // n0x0945 c0x0000 (---------------) + I org 0x0021c783, // n0x0946 c0x0000 (---------------) + I sci 0x000f4e08, // n0x0947 c0x0000 (---------------) + blogspot 0x1622d0c3, // n0x0948 c0x0058 (n0x094d-n0x094e) + I com 0x002325c3, // n0x0949 c0x0000 (---------------) + I edu 0x00210ec3, // n0x094a c0x0000 (---------------) + I gob 0x0020f543, // n0x094b c0x0000 (---------------) + I nom 0x00223a43, // n0x094c c0x0000 (---------------) + I org 0x000f4e08, // n0x094d c0x0000 (---------------) + blogspot 0x00325b83, // n0x094e c0x0000 (---------------) + I biz 0x0022d0c3, // n0x094f c0x0000 (---------------) + I com 0x002325c3, // n0x0950 c0x0000 (---------------) + I edu 0x00264783, // n0x0951 c0x0000 (---------------) + I gov 0x003a4f84, // n0x0952 c0x0000 (---------------) + I info 0x0020ff84, // n0x0953 c0x0000 (---------------) + I name 0x0021e283, // n0x0954 c0x0000 (---------------) + I net 0x00223a43, // n0x0955 c0x0000 (---------------) + I org 0x0031dc85, // n0x0956 c0x0000 (---------------) + I aland 0x000f4e08, // n0x0957 c0x0000 (---------------) + blogspot 0x00002003, // n0x0958 c0x0000 (---------------) + iki 0x003381c8, // n0x0959 c0x0000 (---------------) + I aeroport 0x0034d747, // n0x095a c0x0000 (---------------) + I assedic 0x002c7fc4, // n0x095b c0x0000 (---------------) + I asso 0x003422c6, // n0x095c c0x0000 (---------------) + I avocat 0x0035c106, // n0x095d c0x0000 (---------------) + I avoues 0x000f4e08, // n0x095e c0x0000 (---------------) + blogspot 0x00275503, // n0x095f c0x0000 (---------------) + I cci 0x002ff989, // n0x0960 c0x0000 (---------------) + I chambagri 0x002abfd5, // n0x0961 c0x0000 (---------------) + I chirurgiens-dentistes 0x0022d0c3, // n0x0962 c0x0000 (---------------) + I com 0x0031c112, // n0x0963 c0x0000 (---------------) + I experts-comptables 0x0031becf, // n0x0964 c0x0000 (---------------) + I geometre-expert 0x0034ec04, // n0x0965 c0x0000 (---------------) + I gouv 0x002183c5, // n0x0966 c0x0000 (---------------) + I greta 0x002e7b90, // n0x0967 c0x0000 (---------------) + I huissier-justice 0x0039a747, // n0x0968 c0x0000 (---------------) + I medecin 0x0020f543, // n0x0969 c0x0000 (---------------) + I nom 0x00241c88, // n0x096a c0x0000 (---------------) + I notaires 0x002ed1ca, // n0x096b c0x0000 (---------------) + I pharmacien 0x0023f444, // n0x096c c0x0000 (---------------) + I port 0x002d9d03, // n0x096d c0x0000 (---------------) + I prd 0x002416c6, // n0x096e c0x0000 (---------------) + I presse 0x00200142, // n0x096f c0x0000 (---------------) + I tm 0x0026af0b, // n0x0970 c0x0000 (---------------) + I veterinaire 0x0022d0c3, // n0x0971 c0x0000 (---------------) + I com 0x002325c3, // n0x0972 c0x0000 (---------------) + I edu 0x00264783, // n0x0973 c0x0000 (---------------) + I gov 0x00214d03, // n0x0974 c0x0000 (---------------) + I mil 0x0021e283, // n0x0975 c0x0000 (---------------) + I net 0x00223a43, // n0x0976 c0x0000 (---------------) + I org 0x002de543, // n0x0977 c0x0000 (---------------) + I pvt 0x00203dc2, // n0x0978 c0x0000 (---------------) + I co 0x0021e283, // n0x0979 c0x0000 (---------------) + I net 0x00223a43, // n0x097a c0x0000 (---------------) + I org 0x0022d0c3, // n0x097b c0x0000 (---------------) + I com 0x002325c3, // n0x097c c0x0000 (---------------) + I edu 0x00264783, // n0x097d c0x0000 (---------------) + I gov 0x00214d03, // n0x097e c0x0000 (---------------) + I mil 0x00223a43, // n0x097f c0x0000 (---------------) + I org 0x0022d0c3, // n0x0980 c0x0000 (---------------) + I com 0x002325c3, // n0x0981 c0x0000 (---------------) + I edu 0x00264783, // n0x0982 c0x0000 (---------------) + I gov 0x00314403, // n0x0983 c0x0000 (---------------) + I ltd 0x00213943, // n0x0984 c0x0000 (---------------) + I mod 0x00223a43, // n0x0985 c0x0000 (---------------) + I org 0x00203dc2, // n0x0986 c0x0000 (---------------) + I co 0x0022d0c3, // n0x0987 c0x0000 (---------------) + I com 0x002325c3, // n0x0988 c0x0000 (---------------) + I edu 0x0021e283, // n0x0989 c0x0000 (---------------) + I net 0x00223a43, // n0x098a c0x0000 (---------------) + I org 0x00203982, // n0x098b c0x0000 (---------------) + I ac 0x0022d0c3, // n0x098c c0x0000 (---------------) + I com 0x002325c3, // n0x098d c0x0000 (---------------) + I edu 0x00264783, // n0x098e c0x0000 (---------------) + I gov 0x0021e283, // n0x098f c0x0000 (---------------) + I net 0x00223a43, // n0x0990 c0x0000 (---------------) + I org 0x002c7fc4, // n0x0991 c0x0000 (---------------) + I asso 0x0022d0c3, // n0x0992 c0x0000 (---------------) + I com 0x002325c3, // n0x0993 c0x0000 (---------------) + I edu 0x00207c84, // n0x0994 c0x0000 (---------------) + I mobi 0x0021e283, // n0x0995 c0x0000 (---------------) + I net 0x00223a43, // n0x0996 c0x0000 (---------------) + I org 0x000f4e08, // n0x0997 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x0998 c0x0000 (---------------) + I com 0x002325c3, // n0x0999 c0x0000 (---------------) + I edu 0x00264783, // n0x099a c0x0000 (---------------) + I gov 0x0021e283, // n0x099b c0x0000 (---------------) + I net 0x00223a43, // n0x099c c0x0000 (---------------) + I org 0x0022d0c3, // n0x099d c0x0000 (---------------) + I com 0x002325c3, // n0x099e c0x0000 (---------------) + I edu 0x00210ec3, // n0x099f c0x0000 (---------------) + I gob 0x0021c903, // n0x09a0 c0x0000 (---------------) + I ind 0x00214d03, // n0x09a1 c0x0000 (---------------) + I mil 0x0021e283, // n0x09a2 c0x0000 (---------------) + I net 0x00223a43, // n0x09a3 c0x0000 (---------------) + I org 0x00203dc2, // n0x09a4 c0x0000 (---------------) + I co 0x0022d0c3, // n0x09a5 c0x0000 (---------------) + I com 0x0021e283, // n0x09a6 c0x0000 (---------------) + I net 0x000f4e08, // n0x09a7 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x09a8 c0x0000 (---------------) + I com 0x002325c3, // n0x09a9 c0x0000 (---------------) + I edu 0x00264783, // n0x09aa c0x0000 (---------------) + I gov 0x00310743, // n0x09ab c0x0000 (---------------) + I idv 0x00038f83, // n0x09ac c0x0000 (---------------) + inc 0x00114403, // n0x09ad c0x0000 (---------------) + ltd 0x0021e283, // n0x09ae c0x0000 (---------------) + I net 0x00223a43, // n0x09af c0x0000 (---------------) + I org 0x002f8f8a, // n0x09b0 c0x0000 (---------------) + I xn--55qx5d 0x00315609, // n0x09b1 c0x0000 (---------------) + I xn--ciqpn 0x0033100b, // n0x09b2 c0x0000 (---------------) + I xn--gmq050i 0x0033158a, // n0x09b3 c0x0000 (---------------) + I xn--gmqw5a 0x0033fc0a, // n0x09b4 c0x0000 (---------------) + I xn--io0a7i 0x0035000b, // n0x09b5 c0x0000 (---------------) + I xn--lcvr32d 0x003625ca, // n0x09b6 c0x0000 (---------------) + I xn--mk0axi 0x0036b2ca, // n0x09b7 c0x0000 (---------------) + I xn--mxtq1m 0x003700ca, // n0x09b8 c0x0000 (---------------) + I xn--od0alg 0x0037034b, // n0x09b9 c0x0000 (---------------) + I xn--od0aq3b 0x0038bb49, // n0x09ba c0x0000 (---------------) + I xn--tn0ag 0x0038e60a, // n0x09bb c0x0000 (---------------) + I xn--uc0atv 0x0038eb4b, // n0x09bc c0x0000 (---------------) + I xn--uc0ay4a 0x003993cb, // n0x09bd c0x0000 (---------------) + I xn--wcvs22d 0x003a104a, // n0x09be c0x0000 (---------------) + I xn--zf0avx 0x0022d0c3, // n0x09bf c0x0000 (---------------) + I com 0x002325c3, // n0x09c0 c0x0000 (---------------) + I edu 0x00210ec3, // n0x09c1 c0x0000 (---------------) + I gob 0x00214d03, // n0x09c2 c0x0000 (---------------) + I mil 0x0021e283, // n0x09c3 c0x0000 (---------------) + I net 0x00223a43, // n0x09c4 c0x0000 (---------------) + I org 0x000f4e08, // n0x09c5 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x09c6 c0x0000 (---------------) + I com 0x0025b104, // n0x09c7 c0x0000 (---------------) + I from 0x00215502, // n0x09c8 c0x0000 (---------------) + I iz 0x0020ff84, // n0x09c9 c0x0000 (---------------) + I name 0x0029b705, // n0x09ca c0x0000 (---------------) + I adult 0x00203b03, // n0x09cb c0x0000 (---------------) + I art 0x002c7fc4, // n0x09cc c0x0000 (---------------) + I asso 0x0022d0c3, // n0x09cd c0x0000 (---------------) + I com 0x00235044, // n0x09ce c0x0000 (---------------) + I coop 0x002325c3, // n0x09cf c0x0000 (---------------) + I edu 0x00246bc4, // n0x09d0 c0x0000 (---------------) + I firm 0x0034ec04, // n0x09d1 c0x0000 (---------------) + I gouv 0x003a4f84, // n0x09d2 c0x0000 (---------------) + I info 0x00220d43, // n0x09d3 c0x0000 (---------------) + I med 0x0021e283, // n0x09d4 c0x0000 (---------------) + I net 0x00223a43, // n0x09d5 c0x0000 (---------------) + I org 0x00291545, // n0x09d6 c0x0000 (---------------) + I perso 0x002200c3, // n0x09d7 c0x0000 (---------------) + I pol 0x00220443, // n0x09d8 c0x0000 (---------------) + I pro 0x0027f083, // n0x09d9 c0x0000 (---------------) + I rel 0x00382744, // n0x09da c0x0000 (---------------) + I shop 0x0033a9c4, // n0x09db c0x0000 (---------------) + I 2000 0x0024a5c5, // n0x09dc c0x0000 (---------------) + I agrar 0x000f4e08, // n0x09dd c0x0000 (---------------) + blogspot 0x0020c184, // n0x09de c0x0000 (---------------) + I bolt 0x00373446, // n0x09df c0x0000 (---------------) + I casino 0x002808c4, // n0x09e0 c0x0000 (---------------) + I city 0x00203dc2, // n0x09e1 c0x0000 (---------------) + I co 0x0032d087, // n0x09e2 c0x0000 (---------------) + I erotica 0x00249707, // n0x09e3 c0x0000 (---------------) + I erotika 0x00244544, // n0x09e4 c0x0000 (---------------) + I film 0x00254405, // n0x09e5 c0x0000 (---------------) + I forum 0x00344485, // n0x09e6 c0x0000 (---------------) + I games 0x0022de05, // n0x09e7 c0x0000 (---------------) + I hotel 0x003a4f84, // n0x09e8 c0x0000 (---------------) + I info 0x0033c508, // n0x09e9 c0x0000 (---------------) + I ingatlan 0x00289706, // n0x09ea c0x0000 (---------------) + I jogasz 0x002cc848, // n0x09eb c0x0000 (---------------) + I konyvelo 0x0022e3c5, // n0x09ec c0x0000 (---------------) + I lakas 0x003a15c5, // n0x09ed c0x0000 (---------------) + I media 0x00229684, // n0x09ee c0x0000 (---------------) + I news 0x00223a43, // n0x09ef c0x0000 (---------------) + I org 0x002da7c4, // n0x09f0 c0x0000 (---------------) + I priv 0x0034f1c6, // n0x09f1 c0x0000 (---------------) + I reklam 0x002417c3, // n0x09f2 c0x0000 (---------------) + I sex 0x00382744, // n0x09f3 c0x0000 (---------------) + I shop 0x002946c5, // n0x09f4 c0x0000 (---------------) + I sport 0x00233e84, // n0x09f5 c0x0000 (---------------) + I suli 0x00204504, // n0x09f6 c0x0000 (---------------) + I szex 0x00200142, // n0x09f7 c0x0000 (---------------) + I tm 0x0026e5c6, // n0x09f8 c0x0000 (---------------) + I tozsde 0x003813c6, // n0x09f9 c0x0000 (---------------) + I utazas 0x002ea085, // n0x09fa c0x0000 (---------------) + I video 0x00203982, // n0x09fb c0x0000 (---------------) + I ac 0x00325b83, // n0x09fc c0x0000 (---------------) + I biz 0x1b203dc2, // n0x09fd c0x006c (n0x0a06-n0x0a07) + I co 0x00233984, // n0x09fe c0x0000 (---------------) + I desa 0x00200702, // n0x09ff c0x0000 (---------------) + I go 0x00214d03, // n0x0a00 c0x0000 (---------------) + I mil 0x00265142, // n0x0a01 c0x0000 (---------------) + I my 0x0021e283, // n0x0a02 c0x0000 (---------------) + I net 0x00200282, // n0x0a03 c0x0000 (---------------) + I or 0x00213403, // n0x0a04 c0x0000 (---------------) + I sch 0x002292c3, // n0x0a05 c0x0000 (---------------) + I web 0x000f4e08, // n0x0a06 c0x0000 (---------------) + blogspot 0x000f4e08, // n0x0a07 c0x0000 (---------------) + blogspot 0x00264783, // n0x0a08 c0x0000 (---------------) + I gov 0x00203982, // n0x0a09 c0x0000 (---------------) + I ac 0x1be03dc2, // n0x0a0a c0x006f (n0x0a11-n0x0a12) + I co 0x00264783, // n0x0a0b c0x0000 (---------------) + I gov 0x00260d03, // n0x0a0c c0x0000 (---------------) + I idf 0x00369643, // n0x0a0d c0x0000 (---------------) + I k12 0x00227b44, // n0x0a0e c0x0000 (---------------) + I muni 0x0021e283, // n0x0a0f c0x0000 (---------------) + I net 0x00223a43, // n0x0a10 c0x0000 (---------------) + I org 0x000f4e08, // n0x0a11 c0x0000 (---------------) + blogspot 0x00203982, // n0x0a12 c0x0000 (---------------) + I ac 0x1c603dc2, // n0x0a13 c0x0071 (n0x0a19-n0x0a1b) + I co 0x0022d0c3, // n0x0a14 c0x0000 (---------------) + I com 0x0021e283, // n0x0a15 c0x0000 (---------------) + I net 0x00223a43, // n0x0a16 c0x0000 (---------------) + I org 0x0020b642, // n0x0a17 c0x0000 (---------------) + I tt 0x0020da42, // n0x0a18 c0x0000 (---------------) + I tv 0x00314403, // n0x0a19 c0x0000 (---------------) + I ltd 0x002d2f03, // n0x0a1a c0x0000 (---------------) + I plc 0x00203982, // n0x0a1b c0x0000 (---------------) + I ac 0x000f4e08, // n0x0a1c c0x0000 (---------------) + blogspot 0x00203dc2, // n0x0a1d c0x0000 (---------------) + I co 0x002325c3, // n0x0a1e c0x0000 (---------------) + I edu 0x00246bc4, // n0x0a1f c0x0000 (---------------) + I firm 0x00206943, // n0x0a20 c0x0000 (---------------) + I gen 0x00264783, // n0x0a21 c0x0000 (---------------) + I gov 0x0021c903, // n0x0a22 c0x0000 (---------------) + I ind 0x00214d03, // n0x0a23 c0x0000 (---------------) + I mil 0x0021e283, // n0x0a24 c0x0000 (---------------) + I net 0x00217843, // n0x0a25 c0x0000 (---------------) + I nic 0x00223a43, // n0x0a26 c0x0000 (---------------) + I org 0x0021c703, // n0x0a27 c0x0000 (---------------) + I res 0x001172d3, // n0x0a28 c0x0000 (---------------) + barrel-of-knowledge 0x0011ba54, // n0x0a29 c0x0000 (---------------) + barrell-of-knowledge 0x00020b06, // n0x0a2a c0x0000 (---------------) + dyndns 0x00050147, // n0x0a2b c0x0000 (---------------) + for-our 0x00100309, // n0x0a2c c0x0000 (---------------) + groks-the 0x0012614a, // n0x0a2d c0x0000 (---------------) + groks-this 0x0008264d, // n0x0a2e c0x0000 (---------------) + here-for-more 0x000ef30a, // n0x0a2f c0x0000 (---------------) + knowsitall 0x000636c6, // n0x0a30 c0x0000 (---------------) + selfip 0x001374c6, // n0x0a31 c0x0000 (---------------) + webhop 0x00225c02, // n0x0a32 c0x0000 (---------------) + I eu 0x0022d0c3, // n0x0a33 c0x0000 (---------------) + I com 0x000c5e06, // n0x0a34 c0x0000 (---------------) + github 0x001002c5, // n0x0a35 c0x0000 (---------------) + ngrok 0x00008e43, // n0x0a36 c0x0000 (---------------) + nid 0x00012348, // n0x0a37 c0x0000 (---------------) + pantheon 0x000a97c8, // n0x0a38 c0x0000 (---------------) + sandcats 0x0022d0c3, // n0x0a39 c0x0000 (---------------) + I com 0x002325c3, // n0x0a3a c0x0000 (---------------) + I edu 0x00264783, // n0x0a3b c0x0000 (---------------) + I gov 0x00214d03, // n0x0a3c c0x0000 (---------------) + I mil 0x0021e283, // n0x0a3d c0x0000 (---------------) + I net 0x00223a43, // n0x0a3e c0x0000 (---------------) + I org 0x00203982, // n0x0a3f c0x0000 (---------------) + I ac 0x00203dc2, // n0x0a40 c0x0000 (---------------) + I co 0x00264783, // n0x0a41 c0x0000 (---------------) + I gov 0x00203782, // n0x0a42 c0x0000 (---------------) + I id 0x0021e283, // n0x0a43 c0x0000 (---------------) + I net 0x00223a43, // n0x0a44 c0x0000 (---------------) + I org 0x00213403, // n0x0a45 c0x0000 (---------------) + I sch 0x0035808f, // n0x0a46 c0x0000 (---------------) + I xn--mgba3a4f16a 0x0035844e, // n0x0a47 c0x0000 (---------------) + I xn--mgba3a4fra 0x000f4e08, // n0x0a48 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x0a49 c0x0000 (---------------) + I com 0x00042a87, // n0x0a4a c0x0000 (---------------) + cupcake 0x002325c3, // n0x0a4b c0x0000 (---------------) + I edu 0x00264783, // n0x0a4c c0x0000 (---------------) + I gov 0x00267a43, // n0x0a4d c0x0000 (---------------) + I int 0x0021e283, // n0x0a4e c0x0000 (---------------) + I net 0x00223a43, // n0x0a4f c0x0000 (---------------) + I org 0x0021c683, // n0x0a50 c0x0000 (---------------) + I abr 0x00339b47, // n0x0a51 c0x0000 (---------------) + I abruzzo 0x00200c42, // n0x0a52 c0x0000 (---------------) + I ag 0x0038bd09, // n0x0a53 c0x0000 (---------------) + I agrigento 0x002001c2, // n0x0a54 c0x0000 (---------------) + I al 0x00333a0b, // n0x0a55 c0x0000 (---------------) + I alessandria 0x002dca8a, // n0x0a56 c0x0000 (---------------) + I alto-adige 0x002cccc9, // n0x0a57 c0x0000 (---------------) + I altoadige 0x00200682, // n0x0a58 c0x0000 (---------------) + I an 0x0034d1c6, // n0x0a59 c0x0000 (---------------) + I ancona 0x0039d355, // n0x0a5a c0x0000 (---------------) + I andria-barletta-trani 0x00333b55, // n0x0a5b c0x0000 (---------------) + I andria-trani-barletta 0x0028aa93, // n0x0a5c c0x0000 (---------------) + I andriabarlettatrani 0x003340d3, // n0x0a5d c0x0000 (---------------) + I andriatranibarletta 0x00201bc2, // n0x0a5e c0x0000 (---------------) + I ao 0x00217485, // n0x0a5f c0x0000 (---------------) + I aosta 0x00303e0c, // n0x0a60 c0x0000 (---------------) + I aosta-valley 0x0021748b, // n0x0a61 c0x0000 (---------------) + I aostavalley 0x0023ae45, // n0x0a62 c0x0000 (---------------) + I aoste 0x00200942, // n0x0a63 c0x0000 (---------------) + I ap 0x0027ef82, // n0x0a64 c0x0000 (---------------) + I aq 0x00368406, // n0x0a65 c0x0000 (---------------) + I aquila 0x00202942, // n0x0a66 c0x0000 (---------------) + I ar 0x003a32c6, // n0x0a67 c0x0000 (---------------) + I arezzo 0x00389c8d, // n0x0a68 c0x0000 (---------------) + I ascoli-piceno 0x0034824c, // n0x0a69 c0x0000 (---------------) + I ascolipiceno 0x0021d904, // n0x0a6a c0x0000 (---------------) + I asti 0x00200102, // n0x0a6b c0x0000 (---------------) + I at 0x00202f82, // n0x0a6c c0x0000 (---------------) + I av 0x0021fa88, // n0x0a6d c0x0000 (---------------) + I avellino 0x00201b82, // n0x0a6e c0x0000 (---------------) + I ba 0x0024d706, // n0x0a6f c0x0000 (---------------) + I balsan 0x0024e384, // n0x0a70 c0x0000 (---------------) + I bari 0x0039d515, // n0x0a71 c0x0000 (---------------) + I barletta-trani-andria 0x0028ac13, // n0x0a72 c0x0000 (---------------) + I barlettatraniandria 0x0020d583, // n0x0a73 c0x0000 (---------------) + I bas 0x003250ca, // n0x0a74 c0x0000 (---------------) + I basilicata 0x002fdc87, // n0x0a75 c0x0000 (---------------) + I belluno 0x0027f9c9, // n0x0a76 c0x0000 (---------------) + I benevento 0x00237c87, // n0x0a77 c0x0000 (---------------) + I bergamo 0x002fb3c2, // n0x0a78 c0x0000 (---------------) + I bg 0x00200002, // n0x0a79 c0x0000 (---------------) + I bi 0x003a0546, // n0x0a7a c0x0000 (---------------) + I biella 0x00208b82, // n0x0a7b c0x0000 (---------------) + I bl 0x000f4e08, // n0x0a7c c0x0000 (---------------) + blogspot 0x0020d3c2, // n0x0a7d c0x0000 (---------------) + I bn 0x0020c182, // n0x0a7e c0x0000 (---------------) + I bo 0x0037b7c7, // n0x0a7f c0x0000 (---------------) + I bologna 0x0020e1c7, // n0x0a80 c0x0000 (---------------) + I bolzano 0x0021a945, // n0x0a81 c0x0000 (---------------) + I bozen 0x0021ac42, // n0x0a82 c0x0000 (---------------) + I br 0x0021c6c7, // n0x0a83 c0x0000 (---------------) + I brescia 0x0021c888, // n0x0a84 c0x0000 (---------------) + I brindisi 0x002a0ec2, // n0x0a85 c0x0000 (---------------) + I bs 0x0021e182, // n0x0a86 c0x0000 (---------------) + I bt 0x00229d02, // n0x0a87 c0x0000 (---------------) + I bz 0x00200302, // n0x0a88 c0x0000 (---------------) + I ca 0x00308188, // n0x0a89 c0x0000 (---------------) + I cagliari 0x002178c3, // n0x0a8a c0x0000 (---------------) + I cal 0x0024d348, // n0x0a8b c0x0000 (---------------) + I calabria 0x00232bcd, // n0x0a8c c0x0000 (---------------) + I caltanissetta 0x00229383, // n0x0a8d c0x0000 (---------------) + I cam 0x00310308, // n0x0a8e c0x0000 (---------------) + I campania 0x0023becf, // n0x0a8f c0x0000 (---------------) + I campidano-medio 0x0023c28e, // n0x0a90 c0x0000 (---------------) + I campidanomedio 0x0032c68a, // n0x0a91 c0x0000 (---------------) + I campobasso 0x002e4691, // n0x0a92 c0x0000 (---------------) + I carbonia-iglesias 0x002e4b10, // n0x0a93 c0x0000 (---------------) + I carboniaiglesias 0x002ad7cd, // n0x0a94 c0x0000 (---------------) + I carrara-massa 0x002adb0c, // n0x0a95 c0x0000 (---------------) + I carraramassa 0x00213fc7, // n0x0a96 c0x0000 (---------------) + I caserta 0x00325247, // n0x0a97 c0x0000 (---------------) + I catania 0x00342389, // n0x0a98 c0x0000 (---------------) + I catanzaro 0x0021da02, // n0x0a99 c0x0000 (---------------) + I cb 0x00200782, // n0x0a9a c0x0000 (---------------) + I ce 0x00251d4c, // n0x0a9b c0x0000 (---------------) + I cesena-forli 0x0025204b, // n0x0a9c c0x0000 (---------------) + I cesenaforli 0x00202302, // n0x0a9d c0x0000 (---------------) + I ch 0x002a61c6, // n0x0a9e c0x0000 (---------------) + I chieti 0x002039c2, // n0x0a9f c0x0000 (---------------) + I ci 0x0021f902, // n0x0aa0 c0x0000 (---------------) + I cl 0x00219ec2, // n0x0aa1 c0x0000 (---------------) + I cn 0x00203dc2, // n0x0aa2 c0x0000 (---------------) + I co 0x0022d844, // n0x0aa3 c0x0000 (---------------) + I como 0x0023b047, // n0x0aa4 c0x0000 (---------------) + I cosenza 0x0020ef82, // n0x0aa5 c0x0000 (---------------) + I cr 0x0023dfc7, // n0x0aa6 c0x0000 (---------------) + I cremona 0x0023f247, // n0x0aa7 c0x0000 (---------------) + I crotone 0x00211402, // n0x0aa8 c0x0000 (---------------) + I cs 0x0022f482, // n0x0aa9 c0x0000 (---------------) + I ct 0x00242945, // n0x0aaa c0x0000 (---------------) + I cuneo 0x00235182, // n0x0aab c0x0000 (---------------) + I cz 0x0025370e, // n0x0aac c0x0000 (---------------) + I dell-ogliastra 0x0025e30d, // n0x0aad c0x0000 (---------------) + I dellogliastra 0x002325c3, // n0x0aae c0x0000 (---------------) + I edu 0x003392ce, // n0x0aaf c0x0000 (---------------) + I emilia-romagna 0x0027d74d, // n0x0ab0 c0x0000 (---------------) + I emiliaromagna 0x00350e83, // n0x0ab1 c0x0000 (---------------) + I emr 0x00201dc2, // n0x0ab2 c0x0000 (---------------) + I en 0x00206b84, // n0x0ab3 c0x0000 (---------------) + I enna 0x00243f02, // n0x0ab4 c0x0000 (---------------) + I fc 0x00200382, // n0x0ab5 c0x0000 (---------------) + I fe 0x002d0905, // n0x0ab6 c0x0000 (---------------) + I fermo 0x002db0c7, // n0x0ab7 c0x0000 (---------------) + I ferrara 0x003476c2, // n0x0ab8 c0x0000 (---------------) + I fg 0x00203a42, // n0x0ab9 c0x0000 (---------------) + I fi 0x00246507, // n0x0aba c0x0000 (---------------) + I firenze 0x0024bd48, // n0x0abb c0x0000 (---------------) + I florence 0x0022c142, // n0x0abc c0x0000 (---------------) + I fm 0x003a5006, // n0x0abd c0x0000 (---------------) + I foggia 0x00251bcc, // n0x0abe c0x0000 (---------------) + I forli-cesena 0x00251f0b, // n0x0abf c0x0000 (---------------) + I forlicesena 0x00235842, // n0x0ac0 c0x0000 (---------------) + I fr 0x0025770f, // n0x0ac1 c0x0000 (---------------) + I friuli-v-giulia 0x00257ad0, // n0x0ac2 c0x0000 (---------------) + I friuli-ve-giulia 0x00257ecf, // n0x0ac3 c0x0000 (---------------) + I friuli-vegiulia 0x00258295, // n0x0ac4 c0x0000 (---------------) + I friuli-venezia-giulia 0x002587d4, // n0x0ac5 c0x0000 (---------------) + I friuli-veneziagiulia 0x00258cce, // n0x0ac6 c0x0000 (---------------) + I friuli-vgiulia 0x0025904e, // n0x0ac7 c0x0000 (---------------) + I friuliv-giulia 0x002593cf, // n0x0ac8 c0x0000 (---------------) + I friulive-giulia 0x0025978e, // n0x0ac9 c0x0000 (---------------) + I friulivegiulia 0x00259b14, // n0x0aca c0x0000 (---------------) + I friulivenezia-giulia 0x0025a013, // n0x0acb c0x0000 (---------------) + I friuliveneziagiulia 0x0025a4cd, // n0x0acc c0x0000 (---------------) + I friulivgiulia 0x0026f649, // n0x0acd c0x0000 (---------------) + I frosinone 0x00283603, // n0x0ace c0x0000 (---------------) + I fvg 0x002018c2, // n0x0acf c0x0000 (---------------) + I ge 0x00302b85, // n0x0ad0 c0x0000 (---------------) + I genoa 0x00206946, // n0x0ad1 c0x0000 (---------------) + I genova 0x00200702, // n0x0ad2 c0x0000 (---------------) + I go 0x00260847, // n0x0ad3 c0x0000 (---------------) + I gorizia 0x00264783, // n0x0ad4 c0x0000 (---------------) + I gov 0x002008c2, // n0x0ad5 c0x0000 (---------------) + I gr 0x002f9988, // n0x0ad6 c0x0000 (---------------) + I grosseto 0x002e48d1, // n0x0ad7 c0x0000 (---------------) + I iglesias-carbonia 0x002e4d10, // n0x0ad8 c0x0000 (---------------) + I iglesiascarbonia 0x00207c02, // n0x0ad9 c0x0000 (---------------) + I im 0x00367fc7, // n0x0ada c0x0000 (---------------) + I imperia 0x002011c2, // n0x0adb c0x0000 (---------------) + I is 0x002d4dc7, // n0x0adc c0x0000 (---------------) + I isernia 0x00207b42, // n0x0add c0x0000 (---------------) + I kr 0x002fefc9, // n0x0ade c0x0000 (---------------) + I la-spezia 0x003683c7, // n0x0adf c0x0000 (---------------) + I laquila 0x002519c8, // n0x0ae0 c0x0000 (---------------) + I laspezia 0x00222646, // n0x0ae1 c0x0000 (---------------) + I latina 0x002d2e03, // n0x0ae2 c0x0000 (---------------) + I laz 0x00336c85, // n0x0ae3 c0x0000 (---------------) + I lazio 0x00232842, // n0x0ae4 c0x0000 (---------------) + I lc 0x0020d1c2, // n0x0ae5 c0x0000 (---------------) + I le 0x003a0945, // n0x0ae6 c0x0000 (---------------) + I lecce 0x0021e4c5, // n0x0ae7 c0x0000 (---------------) + I lecco 0x00207d82, // n0x0ae8 c0x0000 (---------------) + I li 0x00233f03, // n0x0ae9 c0x0000 (---------------) + I lig 0x00233f07, // n0x0aea c0x0000 (---------------) + I liguria 0x0020e607, // n0x0aeb c0x0000 (---------------) + I livorno 0x00200242, // n0x0aec c0x0000 (---------------) + I lo 0x00253144, // n0x0aed c0x0000 (---------------) + I lodi 0x00212ac3, // n0x0aee c0x0000 (---------------) + I lom 0x002bf2c9, // n0x0aef c0x0000 (---------------) + I lombardia 0x002d3448, // n0x0af0 c0x0000 (---------------) + I lombardy 0x00200d82, // n0x0af1 c0x0000 (---------------) + I lt 0x00202ac2, // n0x0af2 c0x0000 (---------------) + I lu 0x002a8ac7, // n0x0af3 c0x0000 (---------------) + I lucania 0x002af985, // n0x0af4 c0x0000 (---------------) + I lucca 0x0030fe08, // n0x0af5 c0x0000 (---------------) + I macerata 0x0024b307, // n0x0af6 c0x0000 (---------------) + I mantova 0x00209b83, // n0x0af7 c0x0000 (---------------) + I mar 0x0027c046, // n0x0af8 c0x0000 (---------------) + I marche 0x002ad64d, // n0x0af9 c0x0000 (---------------) + I massa-carrara 0x002ad9cc, // n0x0afa c0x0000 (---------------) + I massacarrara 0x00248a06, // n0x0afb c0x0000 (---------------) + I matera 0x0020a382, // n0x0afc c0x0000 (---------------) + I mb 0x00218742, // n0x0afd c0x0000 (---------------) + I mc 0x00209502, // n0x0afe c0x0000 (---------------) + I me 0x0023bd4f, // n0x0aff c0x0000 (---------------) + I medio-campidano 0x0023c14e, // n0x0b00 c0x0000 (---------------) + I mediocampidano 0x00344507, // n0x0b01 c0x0000 (---------------) + I messina 0x00204142, // n0x0b02 c0x0000 (---------------) + I mi 0x002ebec5, // n0x0b03 c0x0000 (---------------) + I milan 0x002ebec6, // n0x0b04 c0x0000 (---------------) + I milano 0x0021e242, // n0x0b05 c0x0000 (---------------) + I mn 0x00207c82, // n0x0b06 c0x0000 (---------------) + I mo 0x00213946, // n0x0b07 c0x0000 (---------------) + I modena 0x002baac3, // n0x0b08 c0x0000 (---------------) + I mol 0x002d4d06, // n0x0b09 c0x0000 (---------------) + I molise 0x002bdec5, // n0x0b0a c0x0000 (---------------) + I monza 0x002bdecd, // n0x0b0b c0x0000 (---------------) + I monza-brianza 0x002be715, // n0x0b0c c0x0000 (---------------) + I monza-e-della-brianza 0x002beecc, // n0x0b0d c0x0000 (---------------) + I monzabrianza 0x002bfa0d, // n0x0b0e c0x0000 (---------------) + I monzaebrianza 0x002bfdd2, // n0x0b0f c0x0000 (---------------) + I monzaedellabrianza 0x0020bbc2, // n0x0b10 c0x0000 (---------------) + I ms 0x002643c2, // n0x0b11 c0x0000 (---------------) + I mt 0x00201f42, // n0x0b12 c0x0000 (---------------) + I na 0x0036ad46, // n0x0b13 c0x0000 (---------------) + I naples 0x0029f306, // n0x0b14 c0x0000 (---------------) + I napoli 0x00200842, // n0x0b15 c0x0000 (---------------) + I no 0x002069c6, // n0x0b16 c0x0000 (---------------) + I novara 0x002020c2, // n0x0b17 c0x0000 (---------------) + I nu 0x00393745, // n0x0b18 c0x0000 (---------------) + I nuoro 0x00200882, // n0x0b19 c0x0000 (---------------) + I og 0x00253849, // n0x0b1a c0x0000 (---------------) + I ogliastra 0x00266d0c, // n0x0b1b c0x0000 (---------------) + I olbia-tempio 0x0026704b, // n0x0b1c c0x0000 (---------------) + I olbiatempio 0x00200282, // n0x0b1d c0x0000 (---------------) + I or 0x0024c188, // n0x0b1e c0x0000 (---------------) + I oristano 0x00201502, // n0x0b1f c0x0000 (---------------) + I ot 0x00203942, // n0x0b20 c0x0000 (---------------) + I pa 0x00217246, // n0x0b21 c0x0000 (---------------) + I padova 0x0035cf05, // n0x0b22 c0x0000 (---------------) + I padua 0x0022a147, // n0x0b23 c0x0000 (---------------) + I palermo 0x00270a85, // n0x0b24 c0x0000 (---------------) + I parma 0x002cea45, // n0x0b25 c0x0000 (---------------) + I pavia 0x00242b02, // n0x0b26 c0x0000 (---------------) + I pc 0x00382842, // n0x0b27 c0x0000 (---------------) + I pd 0x002087c2, // n0x0b28 c0x0000 (---------------) + I pe 0x0025f587, // n0x0b29 c0x0000 (---------------) + I perugia 0x00226f0d, // n0x0b2a c0x0000 (---------------) + I pesaro-urbino 0x0022728c, // n0x0b2b c0x0000 (---------------) + I pesarourbino 0x00230747, // n0x0b2c c0x0000 (---------------) + I pescara 0x0026b902, // n0x0b2d c0x0000 (---------------) + I pg 0x00218302, // n0x0b2e c0x0000 (---------------) + I pi 0x0032b608, // n0x0b2f c0x0000 (---------------) + I piacenza 0x00252408, // n0x0b30 c0x0000 (---------------) + I piedmont 0x002cf7c8, // n0x0b31 c0x0000 (---------------) + I piemonte 0x002d8344, // n0x0b32 c0x0000 (---------------) + I pisa 0x002a6587, // n0x0b33 c0x0000 (---------------) + I pistoia 0x002d6703, // n0x0b34 c0x0000 (---------------) + I pmn 0x0026b702, // n0x0b35 c0x0000 (---------------) + I pn 0x00208f42, // n0x0b36 c0x0000 (---------------) + I po 0x002d8a09, // n0x0b37 c0x0000 (---------------) + I pordenone 0x00301ec7, // n0x0b38 c0x0000 (---------------) + I potenza 0x002052c2, // n0x0b39 c0x0000 (---------------) + I pr 0x00268b05, // n0x0b3a c0x0000 (---------------) + I prato 0x0026ae82, // n0x0b3b c0x0000 (---------------) + I pt 0x0022ec42, // n0x0b3c c0x0000 (---------------) + I pu 0x00271803, // n0x0b3d c0x0000 (---------------) + I pug 0x00271806, // n0x0b3e c0x0000 (---------------) + I puglia 0x002de542, // n0x0b3f c0x0000 (---------------) + I pv 0x002df1c2, // n0x0b40 c0x0000 (---------------) + I pz 0x00200482, // n0x0b41 c0x0000 (---------------) + I ra 0x00305646, // n0x0b42 c0x0000 (---------------) + I ragusa 0x00206ac7, // n0x0b43 c0x0000 (---------------) + I ravenna 0x002002c2, // n0x0b44 c0x0000 (---------------) + I rc 0x00204902, // n0x0b45 c0x0000 (---------------) + I re 0x0032dccf, // n0x0b46 c0x0000 (---------------) + I reggio-calabria 0x0033910d, // n0x0b47 c0x0000 (---------------) + I reggio-emilia 0x0024d1ce, // n0x0b48 c0x0000 (---------------) + I reggiocalabria 0x0027d5cc, // n0x0b49 c0x0000 (---------------) + I reggioemilia 0x0020a442, // n0x0b4a c0x0000 (---------------) + I rg 0x00205302, // n0x0b4b c0x0000 (---------------) + I ri 0x00222485, // n0x0b4c c0x0000 (---------------) + I rieti 0x002f6dc6, // n0x0b4d c0x0000 (---------------) + I rimini 0x002211c2, // n0x0b4e c0x0000 (---------------) + I rm 0x00208e02, // n0x0b4f c0x0000 (---------------) + I rn 0x00200f82, // n0x0b50 c0x0000 (---------------) + I ro 0x00227684, // n0x0b51 c0x0000 (---------------) + I roma 0x002dbf04, // n0x0b52 c0x0000 (---------------) + I rome 0x003297c6, // n0x0b53 c0x0000 (---------------) + I rovigo 0x00200642, // n0x0b54 c0x0000 (---------------) + I sa 0x0027e007, // n0x0b55 c0x0000 (---------------) + I salerno 0x0021a243, // n0x0b56 c0x0000 (---------------) + I sar 0x0021f288, // n0x0b57 c0x0000 (---------------) + I sardegna 0x00220688, // n0x0b58 c0x0000 (---------------) + I sardinia 0x00367207, // n0x0b59 c0x0000 (---------------) + I sassari 0x0036ac46, // n0x0b5a c0x0000 (---------------) + I savona 0x00209802, // n0x0b5b c0x0000 (---------------) + I si 0x00236d03, // n0x0b5c c0x0000 (---------------) + I sic 0x0036a147, // n0x0b5d c0x0000 (---------------) + I sicilia 0x00242086, // n0x0b5e c0x0000 (---------------) + I sicily 0x002b9605, // n0x0b5f c0x0000 (---------------) + I siena 0x0033f448, // n0x0b60 c0x0000 (---------------) + I siracusa 0x00205bc2, // n0x0b61 c0x0000 (---------------) + I so 0x00314947, // n0x0b62 c0x0000 (---------------) + I sondrio 0x002046c2, // n0x0b63 c0x0000 (---------------) + I sp 0x00329142, // n0x0b64 c0x0000 (---------------) + I sr 0x00201202, // n0x0b65 c0x0000 (---------------) + I ss 0x002c9f89, // n0x0b66 c0x0000 (---------------) + I suedtirol 0x00206ec2, // n0x0b67 c0x0000 (---------------) + I sv 0x00201542, // n0x0b68 c0x0000 (---------------) + I ta 0x002309c3, // n0x0b69 c0x0000 (---------------) + I taa 0x00369247, // n0x0b6a c0x0000 (---------------) + I taranto 0x00200dc2, // n0x0b6b c0x0000 (---------------) + I te 0x00266e8c, // n0x0b6c c0x0000 (---------------) + I tempio-olbia 0x0026718b, // n0x0b6d c0x0000 (---------------) + I tempioolbia 0x00248a86, // n0x0b6e c0x0000 (---------------) + I teramo 0x00208d85, // n0x0b6f c0x0000 (---------------) + I terni 0x0022a482, // n0x0b70 c0x0000 (---------------) + I tn 0x00203b82, // n0x0b71 c0x0000 (---------------) + I to 0x002ab806, // n0x0b72 c0x0000 (---------------) + I torino 0x00227ec3, // n0x0b73 c0x0000 (---------------) + I tos 0x00325447, // n0x0b74 c0x0000 (---------------) + I toscana 0x00212302, // n0x0b75 c0x0000 (---------------) + I tp 0x00202b82, // n0x0b76 c0x0000 (---------------) + I tr 0x0039d1d5, // n0x0b77 c0x0000 (---------------) + I trani-andria-barletta 0x00333d15, // n0x0b78 c0x0000 (---------------) + I trani-barletta-andria 0x0028a953, // n0x0b79 c0x0000 (---------------) + I traniandriabarletta 0x00334253, // n0x0b7a c0x0000 (---------------) + I tranibarlettaandria 0x002947c7, // n0x0b7b c0x0000 (---------------) + I trapani 0x002b4cc8, // n0x0b7c c0x0000 (---------------) + I trentino 0x002e30d0, // n0x0b7d c0x0000 (---------------) + I trentino-a-adige 0x0034014f, // n0x0b7e c0x0000 (---------------) + I trentino-aadige 0x0034b513, // n0x0b7f c0x0000 (---------------) + I trentino-alto-adige 0x002cca92, // n0x0b80 c0x0000 (---------------) + I trentino-altoadige 0x0032f950, // n0x0b81 c0x0000 (---------------) + I trentino-s-tirol 0x002b4ccf, // n0x0b82 c0x0000 (---------------) + I trentino-stirol 0x002bda52, // n0x0b83 c0x0000 (---------------) + I trentino-sud-tirol 0x002c6211, // n0x0b84 c0x0000 (---------------) + I trentino-sudtirol 0x002c8c93, // n0x0b85 c0x0000 (---------------) + I trentino-sued-tirol 0x002c9d52, // n0x0b86 c0x0000 (---------------) + I trentino-suedtirol 0x002cf18f, // n0x0b87 c0x0000 (---------------) + I trentinoa-adige 0x002d868e, // n0x0b88 c0x0000 (---------------) + I trentinoaadige 0x002dc892, // n0x0b89 c0x0000 (---------------) + I trentinoalto-adige 0x002dd0d1, // n0x0b8a c0x0000 (---------------) + I trentinoaltoadige 0x002de5cf, // n0x0b8b c0x0000 (---------------) + I trentinos-tirol 0x002df54e, // n0x0b8c c0x0000 (---------------) + I trentinostirol 0x002e74d1, // n0x0b8d c0x0000 (---------------) + I trentinosud-tirol 0x00331c50, // n0x0b8e c0x0000 (---------------) + I trentinosudtirol 0x002e1312, // n0x0b8f c0x0000 (---------------) + I trentinosued-tirol 0x002f0f91, // n0x0b90 c0x0000 (---------------) + I trentinosuedtirol 0x002ec6c6, // n0x0b91 c0x0000 (---------------) + I trento 0x002eeb47, // n0x0b92 c0x0000 (---------------) + I treviso 0x00362947, // n0x0b93 c0x0000 (---------------) + I trieste 0x00208842, // n0x0b94 c0x0000 (---------------) + I ts 0x00278785, // n0x0b95 c0x0000 (---------------) + I turin 0x002e7907, // n0x0b96 c0x0000 (---------------) + I tuscany 0x0020da42, // n0x0b97 c0x0000 (---------------) + I tv 0x00205f02, // n0x0b98 c0x0000 (---------------) + I ud 0x00226ac5, // n0x0b99 c0x0000 (---------------) + I udine 0x0021d203, // n0x0b9a c0x0000 (---------------) + I umb 0x0024a846, // n0x0b9b c0x0000 (---------------) + I umbria 0x002270cd, // n0x0b9c c0x0000 (---------------) + I urbino-pesaro 0x0022740c, // n0x0b9d c0x0000 (---------------) + I urbinopesaro 0x002000c2, // n0x0b9e c0x0000 (---------------) + I va 0x00303c8b, // n0x0b9f c0x0000 (---------------) + I val-d-aosta 0x0021734a, // n0x0ba0 c0x0000 (---------------) + I val-daosta 0x0031b14a, // n0x0ba1 c0x0000 (---------------) + I vald-aosta 0x002aa709, // n0x0ba2 c0x0000 (---------------) + I valdaosta 0x002d75cb, // n0x0ba3 c0x0000 (---------------) + I valle-aosta 0x002e800d, // n0x0ba4 c0x0000 (---------------) + I valle-d-aosta 0x0024b44c, // n0x0ba5 c0x0000 (---------------) + I valle-daosta 0x0021a3ca, // n0x0ba6 c0x0000 (---------------) + I valleaosta 0x0021fd0c, // n0x0ba7 c0x0000 (---------------) + I valled-aosta 0x00235bcb, // n0x0ba8 c0x0000 (---------------) + I valledaosta 0x0023ac8c, // n0x0ba9 c0x0000 (---------------) + I vallee-aoste 0x00249d4b, // n0x0baa c0x0000 (---------------) + I valleeaoste 0x00266c83, // n0x0bab c0x0000 (---------------) + I vao 0x0026ee06, // n0x0bac c0x0000 (---------------) + I varese 0x002d3f02, // n0x0bad c0x0000 (---------------) + I vb 0x002df902, // n0x0bae c0x0000 (---------------) + I vc 0x0020e543, // n0x0baf c0x0000 (---------------) + I vda 0x00201d82, // n0x0bb0 c0x0000 (---------------) + I ve 0x00201d83, // n0x0bb1 c0x0000 (---------------) + I ven 0x002996c6, // n0x0bb2 c0x0000 (---------------) + I veneto 0x00258447, // n0x0bb3 c0x0000 (---------------) + I venezia 0x0025cf06, // n0x0bb4 c0x0000 (---------------) + I venice 0x0039fe88, // n0x0bb5 c0x0000 (---------------) + I verbania 0x002bc348, // n0x0bb6 c0x0000 (---------------) + I vercelli 0x0020da86, // n0x0bb7 c0x0000 (---------------) + I verona 0x00201302, // n0x0bb8 c0x0000 (---------------) + I vi 0x002e9a4d, // n0x0bb9 c0x0000 (---------------) + I vibo-valentia 0x002e9d8c, // n0x0bba c0x0000 (---------------) + I vibovalentia 0x0034ecc7, // n0x0bbb c0x0000 (---------------) + I vicenza 0x002ef147, // n0x0bbc c0x0000 (---------------) + I viterbo 0x0021a142, // n0x0bbd c0x0000 (---------------) + I vr 0x0022b482, // n0x0bbe c0x0000 (---------------) + I vs 0x0026e582, // n0x0bbf c0x0000 (---------------) + I vt 0x0020c942, // n0x0bc0 c0x0000 (---------------) + I vv 0x00203dc2, // n0x0bc1 c0x0000 (---------------) + I co 0x0021e283, // n0x0bc2 c0x0000 (---------------) + I net 0x00223a43, // n0x0bc3 c0x0000 (---------------) + I org 0x0022d0c3, // n0x0bc4 c0x0000 (---------------) + I com 0x002325c3, // n0x0bc5 c0x0000 (---------------) + I edu 0x00264783, // n0x0bc6 c0x0000 (---------------) + I gov 0x00214d03, // n0x0bc7 c0x0000 (---------------) + I mil 0x0020ff84, // n0x0bc8 c0x0000 (---------------) + I name 0x0021e283, // n0x0bc9 c0x0000 (---------------) + I net 0x00223a43, // n0x0bca c0x0000 (---------------) + I org 0x00213403, // n0x0bcb c0x0000 (---------------) + I sch 0x00203982, // n0x0bcc c0x0000 (---------------) + I ac 0x0020c682, // n0x0bcd c0x0000 (---------------) + I ad 0x1f688645, // n0x0bce c0x007d (n0x0c3b-n0x0c6f) + I aichi 0x1fa026c5, // n0x0bcf c0x007e (n0x0c6f-n0x0c8b) + I akita 0x1ff05306, // n0x0bd0 c0x007f (n0x0c8b-n0x0ca1) + I aomori 0x000f4e08, // n0x0bd1 c0x0000 (---------------) + blogspot 0x202a7dc5, // n0x0bd2 c0x0080 (n0x0ca1-n0x0cdb) + I chiba 0x00203dc2, // n0x0bd3 c0x0000 (---------------) + I co 0x002003c2, // n0x0bd4 c0x0000 (---------------) + I ed 0x20743005, // n0x0bd5 c0x0081 (n0x0cdb-n0x0cf1) + I ehime 0x20a75e05, // n0x0bd6 c0x0082 (n0x0cf1-n0x0d00) + I fukui 0x20e77e47, // n0x0bd7 c0x0083 (n0x0d00-n0x0d3f) + I fukuoka 0x213368c9, // n0x0bd8 c0x0084 (n0x0d3f-n0x0d72) + I fukushima 0x21766a44, // n0x0bd9 c0x0085 (n0x0d72-n0x0d98) + I gifu 0x00200702, // n0x0bda c0x0000 (---------------) + I go 0x002008c2, // n0x0bdb c0x0000 (---------------) + I gr 0x21a3b4c5, // n0x0bdc c0x0086 (n0x0d98-n0x0dbc) + I gunma 0x21e099c9, // n0x0bdd c0x0087 (n0x0dbc-n0x0dd5) + I hiroshima 0x22365a08, // n0x0bde c0x0088 (n0x0dd5-n0x0e63) + I hokkaido 0x226a5e85, // n0x0bdf c0x0089 (n0x0e63-n0x0e91) + I hyogo 0x22abcc07, // n0x0be0 c0x008a (n0x0e91-n0x0ec4) + I ibaraki 0x22e19648, // n0x0be1 c0x008b (n0x0ec4-n0x0ed7) + I ishikawa 0x232d0b85, // n0x0be2 c0x008c (n0x0ed7-n0x0ef9) + I iwate 0x23600c06, // n0x0be3 c0x008d (n0x0ef9-n0x0f08) + I kagawa 0x23a67809, // n0x0be4 c0x008e (n0x0f08-n0x0f1c) + I kagoshima 0x23f09208, // n0x0be5 c0x008f (n0x0f1c-n0x0f3a) + I kanagawa 0x242b3c48, // n0x0be6 c0x0090 (n0x0f3a-n0x0f3b)* o I kawasaki 0x24695cca, // n0x0be7 c0x0091 (n0x0f3b-n0x0f3c)* o I kitakyushu 0x24a48144, // n0x0be8 c0x0092 (n0x0f3c-n0x0f3d)* o I kobe 0x24ec6985, // n0x0be9 c0x0093 (n0x0f3d-n0x0f5c) + I kochi 0x252ad3c8, // n0x0bea c0x0094 (n0x0f5c-n0x0f76) + I kumamoto 0x256b9245, // n0x0beb c0x0095 (n0x0f76-n0x0f95) + I kyoto 0x00217942, // n0x0bec c0x0000 (---------------) + I lg 0x25a40003, // n0x0bed c0x0096 (n0x0f95-n0x0fb3) + I mie 0x25e9c346, // n0x0bee c0x0097 (n0x0fb3-n0x0fd4) + I miyagi 0x2625f0c8, // n0x0bef c0x0098 (n0x0fd4-n0x0fef) + I miyazaki 0x267a40c6, // n0x0bf0 c0x0099 (n0x0fef-n0x103a) + I nagano 0x26abbfc8, // n0x0bf1 c0x009a (n0x103a-n0x1050) + I nagasaki 0x26f04146, // n0x0bf2 c0x009b (n0x1050-n0x1051)* o I nagoya 0x272b96c4, // n0x0bf3 c0x009c (n0x1051-n0x1077) + I nara 0x00201e02, // n0x0bf4 c0x0000 (---------------) + I ne 0x276756c7, // n0x0bf5 c0x009d (n0x1077-n0x1099) + I niigata 0x27aa1f44, // n0x0bf6 c0x009e (n0x1099-n0x10ac) + I oita 0x27e71d87, // n0x0bf7 c0x009f (n0x10ac-n0x10c6) + I okayama 0x2838fc07, // n0x0bf8 c0x00a0 (n0x10c6-n0x10f0) + I okinawa 0x00200282, // n0x0bf9 c0x0000 (---------------) + I or 0x286931c5, // n0x0bfa c0x00a1 (n0x10f0-n0x1122) + I osaka 0x28a06344, // n0x0bfb c0x00a2 (n0x1122-n0x113c) + I saga 0x28f49987, // n0x0bfc c0x00a3 (n0x113c-n0x1181) + I saitama 0x29219147, // n0x0bfd c0x00a4 (n0x1181-n0x1182)* o I sapporo 0x2967b186, // n0x0bfe c0x00a5 (n0x1182-n0x1183)* o I sendai 0x29a283c5, // n0x0bff c0x00a6 (n0x1183-n0x119a) + I shiga 0x29e8d4c7, // n0x0c00 c0x00a7 (n0x119a-n0x11b1) + I shimane 0x2a2a8f48, // n0x0c01 c0x00a8 (n0x11b1-n0x11d5) + I shizuoka 0x2a741547, // n0x0c02 c0x00a9 (n0x11d5-n0x11f4) + I tochigi 0x2ab6fe89, // n0x0c03 c0x00aa (n0x11f4-n0x1205) + I tokushima 0x2af3f685, // n0x0c04 c0x00ab (n0x1205-n0x123e) + I tokyo 0x2b2ec7c7, // n0x0c05 c0x00ac (n0x123e-n0x124b) + I tottori 0x2b687b06, // n0x0c06 c0x00ad (n0x124b-n0x1263) + I toyama 0x2bb3c8c8, // n0x0c07 c0x00ae (n0x1263-n0x1280) + I wakayama 0x003636cd, // n0x0c08 c0x0000 (---------------) + I xn--0trq7p7nn 0x00242c89, // n0x0c09 c0x0000 (---------------) + I xn--1ctwo 0x0034774b, // n0x0c0a c0x0000 (---------------) + I xn--1lqs03n 0x00255b0b, // n0x0c0b c0x0000 (---------------) + I xn--1lqs71d 0x0026c1cb, // n0x0c0c c0x0000 (---------------) + I xn--2m4a15e 0x0029f94b, // n0x0c0d c0x0000 (---------------) + I xn--32vp30h 0x002f76cb, // n0x0c0e c0x0000 (---------------) + I xn--4it168d 0x002f798b, // n0x0c0f c0x0000 (---------------) + I xn--4it797k 0x002f7dc9, // n0x0c10 c0x0000 (---------------) + I xn--4pvxs 0x002f920b, // n0x0c11 c0x0000 (---------------) + I xn--5js045d 0x002f94cb, // n0x0c12 c0x0000 (---------------) + I xn--5rtp49c 0x002fa70b, // n0x0c13 c0x0000 (---------------) + I xn--5rtq34k 0x002fb74a, // n0x0c14 c0x0000 (---------------) + I xn--6btw5a 0x002fbc8a, // n0x0c15 c0x0000 (---------------) + I xn--6orx2r 0x002fc28c, // n0x0c16 c0x0000 (---------------) + I xn--7t0a264c 0x00300d4b, // n0x0c17 c0x0000 (---------------) + I xn--8ltr62k 0x003012ca, // n0x0c18 c0x0000 (---------------) + I xn--8pvr4u 0x0031268a, // n0x0c19 c0x0000 (---------------) + I xn--c3s14m 0x0031f98e, // n0x0c1a c0x0000 (---------------) + I xn--d5qv7z876c 0x0032074e, // n0x0c1b c0x0000 (---------------) + I xn--djrs72d6uy 0x00320aca, // n0x0c1c c0x0000 (---------------) + I xn--djty4k 0x003221ca, // n0x0c1d c0x0000 (---------------) + I xn--efvn9s 0x00322dcb, // n0x0c1e c0x0000 (---------------) + I xn--ehqz56n 0x0032308b, // n0x0c1f c0x0000 (---------------) + I xn--elqq16h 0x00323b8b, // n0x0c20 c0x0000 (---------------) + I xn--f6qx53a 0x0034494b, // n0x0c21 c0x0000 (---------------) + I xn--k7yn95e 0x00344f4a, // n0x0c22 c0x0000 (---------------) + I xn--kbrq7o 0x00345c0b, // n0x0c23 c0x0000 (---------------) + I xn--klt787d 0x00345eca, // n0x0c24 c0x0000 (---------------) + I xn--kltp7d 0x0034614a, // n0x0c25 c0x0000 (---------------) + I xn--kltx9a 0x003463ca, // n0x0c26 c0x0000 (---------------) + I xn--klty5x 0x00363a0b, // n0x0c27 c0x0000 (---------------) + I xn--mkru45i 0x0036bc8b, // n0x0c28 c0x0000 (---------------) + I xn--nit225k 0x0036d8ce, // n0x0c29 c0x0000 (---------------) + I xn--ntso0iqx3a 0x0036dc4b, // n0x0c2a c0x0000 (---------------) + I xn--ntsq17g 0x0037490b, // n0x0c2b c0x0000 (---------------) + I xn--pssu33l 0x00375b4b, // n0x0c2c c0x0000 (---------------) + I xn--qqqt11m 0x00378aca, // n0x0c2d c0x0000 (---------------) + I xn--rht27z 0x00378d49, // n0x0c2e c0x0000 (---------------) + I xn--rht3d 0x00378f8a, // n0x0c2f c0x0000 (---------------) + I xn--rht61e 0x0037a60a, // n0x0c30 c0x0000 (---------------) + I xn--rny31h 0x0038d2cb, // n0x0c31 c0x0000 (---------------) + I xn--tor131o 0x0038ee0b, // n0x0c32 c0x0000 (---------------) + I xn--uist22h 0x0038f54a, // n0x0c33 c0x0000 (---------------) + I xn--uisz3g 0x00390c4b, // n0x0c34 c0x0000 (---------------) + I xn--uuwu58a 0x00395ecb, // n0x0c35 c0x0000 (---------------) + I xn--vgu402c 0x003a0a8b, // n0x0c36 c0x0000 (---------------) + I xn--zbx025d 0x2be79248, // n0x0c37 c0x00af (n0x1280-n0x12a2) + I yamagata 0x2c281dc9, // n0x0c38 c0x00b0 (n0x12a2-n0x12b2) + I yamaguchi 0x2c69b349, // n0x0c39 c0x00b1 (n0x12b2-n0x12ce) + I yamanashi 0x2cb53348, // n0x0c3a c0x00b2 (n0x12ce-n0x12cf)* o I yokohama 0x00329545, // n0x0c3b c0x0000 (---------------) + I aisai 0x00201683, // n0x0c3c c0x0000 (---------------) + I ama 0x00201444, // n0x0c3d c0x0000 (---------------) + I anjo 0x0037b9c5, // n0x0c3e c0x0000 (---------------) + I asuke 0x00366786, // n0x0c3f c0x0000 (---------------) + I chiryu 0x002a6e85, // n0x0c40 c0x0000 (---------------) + I chita 0x002815c4, // n0x0c41 c0x0000 (---------------) + I fuso 0x00260748, // n0x0c42 c0x0000 (---------------) + I gamagori 0x00250005, // n0x0c43 c0x0000 (---------------) + I handa 0x0028a504, // n0x0c44 c0x0000 (---------------) + I hazu 0x002be3c7, // n0x0c45 c0x0000 (---------------) + I hekinan 0x0029660a, // n0x0c46 c0x0000 (---------------) + I higashiura 0x0026b40a, // n0x0c47 c0x0000 (---------------) + I ichinomiya 0x002fcdc7, // n0x0c48 c0x0000 (---------------) + I inazawa 0x00202087, // n0x0c49 c0x0000 (---------------) + I inuyama 0x002e6107, // n0x0c4a c0x0000 (---------------) + I isshiki 0x002277c7, // n0x0c4b c0x0000 (---------------) + I iwakura 0x00287885, // n0x0c4c c0x0000 (---------------) + I kanie 0x00325846, // n0x0c4d c0x0000 (---------------) + I kariya 0x00317f87, // n0x0c4e c0x0000 (---------------) + I kasugai 0x00248d44, // n0x0c4f c0x0000 (---------------) + I kira 0x00353186, // n0x0c50 c0x0000 (---------------) + I kiyosu 0x002a40c6, // n0x0c51 c0x0000 (---------------) + I komaki 0x00207ec5, // n0x0c52 c0x0000 (---------------) + I konan 0x00256604, // n0x0c53 c0x0000 (---------------) + I kota 0x0029d806, // n0x0c54 c0x0000 (---------------) + I mihama 0x00295807, // n0x0c55 c0x0000 (---------------) + I miyoshi 0x00224986, // n0x0c56 c0x0000 (---------------) + I nishio 0x002dee07, // n0x0c57 c0x0000 (---------------) + I nisshin 0x00274b43, // n0x0c58 c0x0000 (---------------) + I obu 0x0024b946, // n0x0c59 c0x0000 (---------------) + I oguchi 0x00231205, // n0x0c5a c0x0000 (---------------) + I oharu 0x00277f47, // n0x0c5b c0x0000 (---------------) + I okazaki 0x002b998a, // n0x0c5c c0x0000 (---------------) + I owariasahi 0x002a87c4, // n0x0c5d c0x0000 (---------------) + I seto 0x00217b48, // n0x0c5e c0x0000 (---------------) + I shikatsu 0x0032e749, // n0x0c5f c0x0000 (---------------) + I shinshiro 0x002d28c7, // n0x0c60 c0x0000 (---------------) + I shitara 0x002e0c86, // n0x0c61 c0x0000 (---------------) + I tahara 0x00359a08, // n0x0c62 c0x0000 (---------------) + I takahama 0x00302f09, // n0x0c63 c0x0000 (---------------) + I tobishima 0x002758c4, // n0x0c64 c0x0000 (---------------) + I toei 0x002f6144, // n0x0c65 c0x0000 (---------------) + I togo 0x002efe85, // n0x0c66 c0x0000 (---------------) + I tokai 0x002ba088, // n0x0c67 c0x0000 (---------------) + I tokoname 0x002bad47, // n0x0c68 c0x0000 (---------------) + I toyoake 0x0027f609, // n0x0c69 c0x0000 (---------------) + I toyohashi 0x00242748, // n0x0c6a c0x0000 (---------------) + I toyokawa 0x00361f46, // n0x0c6b c0x0000 (---------------) + I toyone 0x0025d5c6, // n0x0c6c c0x0000 (---------------) + I toyota 0x0028ff08, // n0x0c6d c0x0000 (---------------) + I tsushima 0x00366306, // n0x0c6e c0x0000 (---------------) + I yatomi 0x002026c5, // n0x0c6f c0x0000 (---------------) + I akita 0x0027b246, // n0x0c70 c0x0000 (---------------) + I daisen 0x00272088, // n0x0c71 c0x0000 (---------------) + I fujisato 0x002329c6, // n0x0c72 c0x0000 (---------------) + I gojome 0x0025120b, // n0x0c73 c0x0000 (---------------) + I hachirogata 0x002847c6, // n0x0c74 c0x0000 (---------------) + I happou 0x0029190d, // n0x0c75 c0x0000 (---------------) + I higashinaruse 0x00393b45, // n0x0c76 c0x0000 (---------------) + I honjo 0x002a1e06, // n0x0c77 c0x0000 (---------------) + I honjyo 0x00219705, // n0x0c78 c0x0000 (---------------) + I ikawa 0x0028f009, // n0x0c79 c0x0000 (---------------) + I kamikoani 0x00314007, // n0x0c7a c0x0000 (---------------) + I kamioka 0x00371c88, // n0x0c7b c0x0000 (---------------) + I katagami 0x002fc706, // n0x0c7c c0x0000 (---------------) + I kazuno 0x00290889, // n0x0c7d c0x0000 (---------------) + I kitaakita 0x002dbc86, // n0x0c7e c0x0000 (---------------) + I kosaka 0x002b9905, // n0x0c7f c0x0000 (---------------) + I kyowa 0x00298846, // n0x0c80 c0x0000 (---------------) + I misato 0x002a1106, // n0x0c81 c0x0000 (---------------) + I mitane 0x002c2a09, // n0x0c82 c0x0000 (---------------) + I moriyoshi 0x00333246, // n0x0c83 c0x0000 (---------------) + I nikaho 0x00357d87, // n0x0c84 c0x0000 (---------------) + I noshiro 0x002ab5c5, // n0x0c85 c0x0000 (---------------) + I odate 0x00201c03, // n0x0c86 c0x0000 (---------------) + I oga 0x00222885, // n0x0c87 c0x0000 (---------------) + I ogata 0x002a0007, // n0x0c88 c0x0000 (---------------) + I semboku 0x00342ec6, // n0x0c89 c0x0000 (---------------) + I yokote 0x00393a49, // n0x0c8a c0x0000 (---------------) + I yurihonjo 0x00305306, // n0x0c8b c0x0000 (---------------) + I aomori 0x00247846, // n0x0c8c c0x0000 (---------------) + I gonohe 0x0020aec9, // n0x0c8d c0x0000 (---------------) + I hachinohe 0x0027ac49, // n0x0c8e c0x0000 (---------------) + I hashikami 0x00298fc7, // n0x0c8f c0x0000 (---------------) + I hiranai 0x00337e08, // n0x0c90 c0x0000 (---------------) + I hirosaki 0x002571c9, // n0x0c91 c0x0000 (---------------) + I itayanagi 0x00278408, // n0x0c92 c0x0000 (---------------) + I kuroishi 0x0036b506, // n0x0c93 c0x0000 (---------------) + I misawa 0x002ca5c5, // n0x0c94 c0x0000 (---------------) + I mutsu 0x0021d5ca, // n0x0c95 c0x0000 (---------------) + I nakadomari 0x002478c6, // n0x0c96 c0x0000 (---------------) + I noheji 0x00398606, // n0x0c97 c0x0000 (---------------) + I oirase 0x0029c505, // n0x0c98 c0x0000 (---------------) + I owani 0x00366d88, // n0x0c99 c0x0000 (---------------) + I rokunohe 0x00209607, // n0x0c9a c0x0000 (---------------) + I sannohe 0x0023014a, // n0x0c9b c0x0000 (---------------) + I shichinohe 0x00247746, // n0x0c9c c0x0000 (---------------) + I shingo 0x00235e05, // n0x0c9d c0x0000 (---------------) + I takko 0x00395946, // n0x0c9e c0x0000 (---------------) + I towada 0x002a4807, // n0x0c9f c0x0000 (---------------) + I tsugaru 0x002e0b47, // n0x0ca0 c0x0000 (---------------) + I tsuruta 0x00357a05, // n0x0ca1 c0x0000 (---------------) + I abiko 0x002b9ac5, // n0x0ca2 c0x0000 (---------------) + I asahi 0x002d2f86, // n0x0ca3 c0x0000 (---------------) + I chonan 0x002dea06, // n0x0ca4 c0x0000 (---------------) + I chosei 0x002df946, // n0x0ca5 c0x0000 (---------------) + I choshi 0x00321084, // n0x0ca6 c0x0000 (---------------) + I chuo 0x00279d09, // n0x0ca7 c0x0000 (---------------) + I funabashi 0x00282c86, // n0x0ca8 c0x0000 (---------------) + I futtsu 0x0027b80a, // n0x0ca9 c0x0000 (---------------) + I hanamigawa 0x00288688, // n0x0caa c0x0000 (---------------) + I ichihara 0x0032d348, // n0x0cab c0x0000 (---------------) + I ichikawa 0x0026b40a, // n0x0cac c0x0000 (---------------) + I ichinomiya 0x00397ec5, // n0x0cad c0x0000 (---------------) + I inzai 0x00295745, // n0x0cae c0x0000 (---------------) + I isumi 0x00303788, // n0x0caf c0x0000 (---------------) + I kamagaya 0x002c6708, // n0x0cb0 c0x0000 (---------------) + I kamogawa 0x0031d8c7, // n0x0cb1 c0x0000 (---------------) + I kashiwa 0x00294b46, // n0x0cb2 c0x0000 (---------------) + I katori 0x0030d588, // n0x0cb3 c0x0000 (---------------) + I katsuura 0x0034e3c7, // n0x0cb4 c0x0000 (---------------) + I kimitsu 0x00279708, // n0x0cb5 c0x0000 (---------------) + I kisarazu 0x00364a06, // n0x0cb6 c0x0000 (---------------) + I kozaki 0x0027bdc8, // n0x0cb7 c0x0000 (---------------) + I kujukuri 0x0028ca06, // n0x0cb8 c0x0000 (---------------) + I kyonan 0x0022e547, // n0x0cb9 c0x0000 (---------------) + I matsudo 0x002912c6, // n0x0cba c0x0000 (---------------) + I midori 0x0029d806, // n0x0cbb c0x0000 (---------------) + I mihama 0x0022c18a, // n0x0cbc c0x0000 (---------------) + I minamiboso 0x0022d8c6, // n0x0cbd c0x0000 (---------------) + I mobara 0x002ca5c9, // n0x0cbe c0x0000 (---------------) + I mutsuzawa 0x002a80c6, // n0x0cbf c0x0000 (---------------) + I nagara 0x002cba8a, // n0x0cc0 c0x0000 (---------------) + I nagareyama 0x002b96c9, // n0x0cc1 c0x0000 (---------------) + I narashino 0x00357106, // n0x0cc2 c0x0000 (---------------) + I narita 0x00376fc4, // n0x0cc3 c0x0000 (---------------) + I noda 0x00302c4d, // n0x0cc4 c0x0000 (---------------) + I oamishirasato 0x00282047, // n0x0cc5 c0x0000 (---------------) + I omigawa 0x0030fb86, // n0x0cc6 c0x0000 (---------------) + I onjuku 0x002b3b05, // n0x0cc7 c0x0000 (---------------) + I otaki 0x002dbd05, // n0x0cc8 c0x0000 (---------------) + I sakae 0x002d4206, // n0x0cc9 c0x0000 (---------------) + I sakura 0x00287249, // n0x0cca c0x0000 (---------------) + I shimofusa 0x0029be87, // n0x0ccb c0x0000 (---------------) + I shirako 0x00272cc6, // n0x0ccc c0x0000 (---------------) + I shiroi 0x002eda06, // n0x0ccd c0x0000 (---------------) + I shisui 0x00281649, // n0x0cce c0x0000 (---------------) + I sodegaura 0x0021c104, // n0x0ccf c0x0000 (---------------) + I sosa 0x00224804, // n0x0cd0 c0x0000 (---------------) + I tako 0x00201548, // n0x0cd1 c0x0000 (---------------) + I tateyama 0x00299a86, // n0x0cd2 c0x0000 (---------------) + I togane 0x00298948, // n0x0cd3 c0x0000 (---------------) + I tohnosho 0x002aee08, // n0x0cd4 c0x0000 (---------------) + I tomisato 0x0026dbc7, // n0x0cd5 c0x0000 (---------------) + I urayasu 0x003a1c89, // n0x0cd6 c0x0000 (---------------) + I yachimata 0x002dfb47, // n0x0cd7 c0x0000 (---------------) + I yachiyo 0x002a7c8a, // n0x0cd8 c0x0000 (---------------) + I yokaichiba 0x002ae7cf, // n0x0cd9 c0x0000 (---------------) + I yokoshibahikari 0x0026194a, // n0x0cda c0x0000 (---------------) + I yotsukaido 0x00222285, // n0x0cdb c0x0000 (---------------) + I ainan 0x002722c5, // n0x0cdc c0x0000 (---------------) + I honai 0x00216e45, // n0x0cdd c0x0000 (---------------) + I ikata 0x0024e2c7, // n0x0cde c0x0000 (---------------) + I imabari 0x00274303, // n0x0cdf c0x0000 (---------------) + I iyo 0x00338008, // n0x0ce0 c0x0000 (---------------) + I kamijima 0x002ea686, // n0x0ce1 c0x0000 (---------------) + I kihoku 0x002ea789, // n0x0ce2 c0x0000 (---------------) + I kumakogen 0x0039f646, // n0x0ce3 c0x0000 (---------------) + I masaki 0x002ba487, // n0x0ce4 c0x0000 (---------------) + I matsuno 0x00290649, // n0x0ce5 c0x0000 (---------------) + I matsuyama 0x00371b88, // n0x0ce6 c0x0000 (---------------) + I namikata 0x0029c5c7, // n0x0ce7 c0x0000 (---------------) + I niihama 0x002f66c3, // n0x0ce8 c0x0000 (---------------) + I ozu 0x003295c5, // n0x0ce9 c0x0000 (---------------) + I saijo 0x0039b245, // n0x0cea c0x0000 (---------------) + I seiyo 0x00320ecb, // n0x0ceb c0x0000 (---------------) + I shikokuchuo 0x002b9304, // n0x0cec c0x0000 (---------------) + I tobe 0x00203b84, // n0x0ced c0x0000 (---------------) + I toon 0x00271046, // n0x0cee c0x0000 (---------------) + I uchiko 0x002f6a47, // n0x0cef c0x0000 (---------------) + I uwajima 0x003883ca, // n0x0cf0 c0x0000 (---------------) + I yawatahama 0x00240087, // n0x0cf1 c0x0000 (---------------) + I echizen 0x00275947, // n0x0cf2 c0x0000 (---------------) + I eiheiji 0x00275e05, // n0x0cf3 c0x0000 (---------------) + I fukui 0x00201785, // n0x0cf4 c0x0000 (---------------) + I ikeda 0x00214fc9, // n0x0cf5 c0x0000 (---------------) + I katsuyama 0x0029d806, // n0x0cf6 c0x0000 (---------------) + I mihama 0x0023ff0d, // n0x0cf7 c0x0000 (---------------) + I minamiechizen 0x0038ffc5, // n0x0cf8 c0x0000 (---------------) + I obama 0x00298b43, // n0x0cf9 c0x0000 (---------------) + I ohi 0x0020f703, // n0x0cfa c0x0000 (---------------) + I ono 0x002eb005, // n0x0cfb c0x0000 (---------------) + I sabae 0x00348a85, // n0x0cfc c0x0000 (---------------) + I sakai 0x00359a08, // n0x0cfd c0x0000 (---------------) + I takahama 0x002739c7, // n0x0cfe c0x0000 (---------------) + I tsuruga 0x00224586, // n0x0cff c0x0000 (---------------) + I wakasa 0x00296cc6, // n0x0d00 c0x0000 (---------------) + I ashiya 0x00228585, // n0x0d01 c0x0000 (---------------) + I buzen 0x00232887, // n0x0d02 c0x0000 (---------------) + I chikugo 0x00202307, // n0x0d03 c0x0000 (---------------) + I chikuho 0x002895c7, // n0x0d04 c0x0000 (---------------) + I chikujo 0x002c6a0a, // n0x0d05 c0x0000 (---------------) + I chikushino 0x0024ba08, // n0x0d06 c0x0000 (---------------) + I chikuzen 0x00321084, // n0x0d07 c0x0000 (---------------) + I chuo 0x0020cac7, // n0x0d08 c0x0000 (---------------) + I dazaifu 0x00274c87, // n0x0d09 c0x0000 (---------------) + I fukuchi 0x00305b46, // n0x0d0a c0x0000 (---------------) + I hakata 0x0025fc07, // n0x0d0b c0x0000 (---------------) + I higashi 0x002c0c08, // n0x0d0c c0x0000 (---------------) + I hirokawa 0x0029b248, // n0x0d0d c0x0000 (---------------) + I hisayama 0x00260206, // n0x0d0e c0x0000 (---------------) + I iizuka 0x00218c48, // n0x0d0f c0x0000 (---------------) + I inatsuki 0x002c25c4, // n0x0d10 c0x0000 (---------------) + I kaho 0x00317f86, // n0x0d11 c0x0000 (---------------) + I kasuga 0x002088c6, // n0x0d12 c0x0000 (---------------) + I kasuya 0x00392bc6, // n0x0d13 c0x0000 (---------------) + I kawara 0x00326546, // n0x0d14 c0x0000 (---------------) + I keisen 0x0021f544, // n0x0d15 c0x0000 (---------------) + I koga 0x00227886, // n0x0d16 c0x0000 (---------------) + I kurate 0x002b2986, // n0x0d17 c0x0000 (---------------) + I kurogi 0x0028f686, // n0x0d18 c0x0000 (---------------) + I kurume 0x00228206, // n0x0d19 c0x0000 (---------------) + I minami 0x0020f5c6, // n0x0d1a c0x0000 (---------------) + I miyako 0x002c0a46, // n0x0d1b c0x0000 (---------------) + I miyama 0x00224488, // n0x0d1c c0x0000 (---------------) + I miyawaka 0x00353008, // n0x0d1d c0x0000 (---------------) + I mizumaki 0x002c75c8, // n0x0d1e c0x0000 (---------------) + I munakata 0x002a7088, // n0x0d1f c0x0000 (---------------) + I nakagawa 0x00303706, // n0x0d20 c0x0000 (---------------) + I nakama 0x00211505, // n0x0d21 c0x0000 (---------------) + I nishi 0x00222846, // n0x0d22 c0x0000 (---------------) + I nogata 0x002a5f05, // n0x0d23 c0x0000 (---------------) + I ogori 0x00377f07, // n0x0d24 c0x0000 (---------------) + I okagaki 0x00242805, // n0x0d25 c0x0000 (---------------) + I okawa 0x002107c3, // n0x0d26 c0x0000 (---------------) + I oki 0x00209105, // n0x0d27 c0x0000 (---------------) + I omuta 0x002af784, // n0x0d28 c0x0000 (---------------) + I onga 0x0020f705, // n0x0d29 c0x0000 (---------------) + I onojo 0x002128c3, // n0x0d2a c0x0000 (---------------) + I oto 0x002d6e07, // n0x0d2b c0x0000 (---------------) + I saigawa 0x003440c8, // n0x0d2c c0x0000 (---------------) + I sasaguri 0x002deec6, // n0x0d2d c0x0000 (---------------) + I shingu 0x0028750d, // n0x0d2e c0x0000 (---------------) + I shinyoshitomi 0x00272286, // n0x0d2f c0x0000 (---------------) + I shonai 0x0028e705, // n0x0d30 c0x0000 (---------------) + I soeda 0x002c2dc3, // n0x0d31 c0x0000 (---------------) + I sue 0x002acd89, // n0x0d32 c0x0000 (---------------) + I tachiarai 0x002bcdc6, // n0x0d33 c0x0000 (---------------) + I tagawa 0x0028ed06, // n0x0d34 c0x0000 (---------------) + I takata 0x00348fc4, // n0x0d35 c0x0000 (---------------) + I toho 0x002618c7, // n0x0d36 c0x0000 (---------------) + I toyotsu 0x00233bc6, // n0x0d37 c0x0000 (---------------) + I tsuiki 0x00366bc5, // n0x0d38 c0x0000 (---------------) + I ukiha 0x00204103, // n0x0d39 c0x0000 (---------------) + I umi 0x00201104, // n0x0d3a c0x0000 (---------------) + I usui 0x00274e46, // n0x0d3b c0x0000 (---------------) + I yamada 0x00292104, // n0x0d3c c0x0000 (---------------) + I yame 0x00307288, // n0x0d3d c0x0000 (---------------) + I yanagawa 0x0031ce49, // n0x0d3e c0x0000 (---------------) + I yukuhashi 0x002b9009, // n0x0d3f c0x0000 (---------------) + I aizubange 0x0029874a, // n0x0d40 c0x0000 (---------------) + I aizumisato 0x0023e68d, // n0x0d41 c0x0000 (---------------) + I aizuwakamatsu 0x0024db87, // n0x0d42 c0x0000 (---------------) + I asakawa 0x00398486, // n0x0d43 c0x0000 (---------------) + I bandai 0x0020b444, // n0x0d44 c0x0000 (---------------) + I date 0x003368c9, // n0x0d45 c0x0000 (---------------) + I fukushima 0x00280248, // n0x0d46 c0x0000 (---------------) + I furudono 0x00281c46, // n0x0d47 c0x0000 (---------------) + I futaba 0x00253ac6, // n0x0d48 c0x0000 (---------------) + I hanawa 0x0025fc07, // n0x0d49 c0x0000 (---------------) + I higashi 0x002a3406, // n0x0d4a c0x0000 (---------------) + I hirata 0x0021b346, // n0x0d4b c0x0000 (---------------) + I hirono 0x0031d146, // n0x0d4c c0x0000 (---------------) + I iitate 0x0038fc8a, // n0x0d4d c0x0000 (---------------) + I inawashiro 0x00219648, // n0x0d4e c0x0000 (---------------) + I ishikawa 0x00228785, // n0x0d4f c0x0000 (---------------) + I iwaki 0x0026d909, // n0x0d50 c0x0000 (---------------) + I izumizaki 0x002bb4ca, // n0x0d51 c0x0000 (---------------) + I kagamiishi 0x002c3a08, // n0x0d52 c0x0000 (---------------) + I kaneyama 0x00293f88, // n0x0d53 c0x0000 (---------------) + I kawamata 0x0028ec88, // n0x0d54 c0x0000 (---------------) + I kitakata 0x0020270c, // n0x0d55 c0x0000 (---------------) + I kitashiobara 0x002ed605, // n0x0d56 c0x0000 (---------------) + I koori 0x00296f48, // n0x0d57 c0x0000 (---------------) + I koriyama 0x002ebdc6, // n0x0d58 c0x0000 (---------------) + I kunimi 0x002a1846, // n0x0d59 c0x0000 (---------------) + I miharu 0x0039de07, // n0x0d5a c0x0000 (---------------) + I mishima 0x0023ff85, // n0x0d5b c0x0000 (---------------) + I namie 0x0027b3c5, // n0x0d5c c0x0000 (---------------) + I nango 0x002b8ec9, // n0x0d5d c0x0000 (---------------) + I nishiaizu 0x00212147, // n0x0d5e c0x0000 (---------------) + I nishigo 0x002ea745, // n0x0d5f c0x0000 (---------------) + I okuma 0x0021be07, // n0x0d60 c0x0000 (---------------) + I omotego 0x0020f703, // n0x0d61 c0x0000 (---------------) + I ono 0x002bb985, // n0x0d62 c0x0000 (---------------) + I otama 0x00342108, // n0x0d63 c0x0000 (---------------) + I samegawa 0x00312fc7, // n0x0d64 c0x0000 (---------------) + I shimogo 0x00293e49, // n0x0d65 c0x0000 (---------------) + I shirakawa 0x002aadc5, // n0x0d66 c0x0000 (---------------) + I showa 0x002ef044, // n0x0d67 c0x0000 (---------------) + I soma 0x0029a088, // n0x0d68 c0x0000 (---------------) + I sukagawa 0x00214107, // n0x0d69 c0x0000 (---------------) + I taishin 0x0029c788, // n0x0d6a c0x0000 (---------------) + I tamakawa 0x00325f48, // n0x0d6b c0x0000 (---------------) + I tanagura 0x00349fc5, // n0x0d6c c0x0000 (---------------) + I tenei 0x0034d4c6, // n0x0d6d c0x0000 (---------------) + I yabuki 0x002881c6, // n0x0d6e c0x0000 (---------------) + I yamato 0x00254cc9, // n0x0d6f c0x0000 (---------------) + I yamatsuri 0x0030de07, // n0x0d70 c0x0000 (---------------) + I yanaizu 0x002a6786, // n0x0d71 c0x0000 (---------------) + I yugawa 0x002866c7, // n0x0d72 c0x0000 (---------------) + I anpachi 0x00213a03, // n0x0d73 c0x0000 (---------------) + I ena 0x00366a44, // n0x0d74 c0x0000 (---------------) + I gifu 0x0029a9c5, // n0x0d75 c0x0000 (---------------) + I ginan 0x0020cd44, // n0x0d76 c0x0000 (---------------) + I godo 0x0022c744, // n0x0d77 c0x0000 (---------------) + I gujo 0x002794c7, // n0x0d78 c0x0000 (---------------) + I hashima 0x00212f07, // n0x0d79 c0x0000 (---------------) + I hichiso 0x00272e84, // n0x0d7a c0x0000 (---------------) + I hida 0x00293c90, // n0x0d7b c0x0000 (---------------) + I higashishirakawa 0x00239d07, // n0x0d7c c0x0000 (---------------) + I ibigawa 0x00201785, // n0x0d7d c0x0000 (---------------) + I ikeda 0x002e37cc, // n0x0d7e c0x0000 (---------------) + I kakamigahara 0x0027e584, // n0x0d7f c0x0000 (---------------) + I kani 0x0037b208, // n0x0d80 c0x0000 (---------------) + I kasahara 0x0022e449, // n0x0d81 c0x0000 (---------------) + I kasamatsu 0x002f7546, // n0x0d82 c0x0000 (---------------) + I kawaue 0x0021c208, // n0x0d83 c0x0000 (---------------) + I kitagata 0x00247244, // n0x0d84 c0x0000 (---------------) + I mino 0x00247248, // n0x0d85 c0x0000 (---------------) + I minokamo 0x002ba646, // n0x0d86 c0x0000 (---------------) + I mitake 0x00228088, // n0x0d87 c0x0000 (---------------) + I mizunami 0x0029a6c6, // n0x0d88 c0x0000 (---------------) + I motosu 0x0022a4cb, // n0x0d89 c0x0000 (---------------) + I nakatsugawa 0x00201c05, // n0x0d8a c0x0000 (---------------) + I ogaki 0x002c2548, // n0x0d8b c0x0000 (---------------) + I sakahogi 0x00216244, // n0x0d8c c0x0000 (---------------) + I seki 0x0027a8ca, // n0x0d8d c0x0000 (---------------) + I sekigahara 0x00293e49, // n0x0d8e c0x0000 (---------------) + I shirakawa 0x002f9e46, // n0x0d8f c0x0000 (---------------) + I tajimi 0x002ba308, // n0x0d90 c0x0000 (---------------) + I takayama 0x0026cf85, // n0x0d91 c0x0000 (---------------) + I tarui 0x00221944, // n0x0d92 c0x0000 (---------------) + I toki 0x0037b106, // n0x0d93 c0x0000 (---------------) + I tomika 0x00289488, // n0x0d94 c0x0000 (---------------) + I wanouchi 0x00279248, // n0x0d95 c0x0000 (---------------) + I yamagata 0x0033f1c6, // n0x0d96 c0x0000 (---------------) + I yaotsu 0x00313804, // n0x0d97 c0x0000 (---------------) + I yoro 0x0021d546, // n0x0d98 c0x0000 (---------------) + I annaka 0x002dfbc7, // n0x0d99 c0x0000 (---------------) + I chiyoda 0x00271c87, // n0x0d9a c0x0000 (---------------) + I fujioka 0x0025fc0f, // n0x0d9b c0x0000 (---------------) + I higashiagatsuma 0x00205347, // n0x0d9c c0x0000 (---------------) + I isesaki 0x003571c7, // n0x0d9d c0x0000 (---------------) + I itakura 0x002a1705, // n0x0d9e c0x0000 (---------------) + I kanna 0x002cfb85, // n0x0d9f c0x0000 (---------------) + I kanra 0x00298c89, // n0x0da0 c0x0000 (---------------) + I katashina 0x00263406, // n0x0da1 c0x0000 (---------------) + I kawaba 0x00278b05, // n0x0da2 c0x0000 (---------------) + I kiryu 0x0027af47, // n0x0da3 c0x0000 (---------------) + I kusatsu 0x002ab388, // n0x0da4 c0x0000 (---------------) + I maebashi 0x002b5c85, // n0x0da5 c0x0000 (---------------) + I meiwa 0x002912c6, // n0x0da6 c0x0000 (---------------) + I midori 0x00211d08, // n0x0da7 c0x0000 (---------------) + I minakami 0x003a40ca, // n0x0da8 c0x0000 (---------------) + I naganohara 0x0024e908, // n0x0da9 c0x0000 (---------------) + I nakanojo 0x0038f147, // n0x0daa c0x0000 (---------------) + I nanmoku 0x002aec06, // n0x0dab c0x0000 (---------------) + I numata 0x0026d8c6, // n0x0dac c0x0000 (---------------) + I oizumi 0x0021aec3, // n0x0dad c0x0000 (---------------) + I ora 0x00201503, // n0x0dae c0x0000 (---------------) + I ota 0x002bb689, // n0x0daf c0x0000 (---------------) + I shibukawa 0x00257049, // n0x0db0 c0x0000 (---------------) + I shimonita 0x0036fd86, // n0x0db1 c0x0000 (---------------) + I shinto 0x002aadc5, // n0x0db2 c0x0000 (---------------) + I showa 0x0029a448, // n0x0db3 c0x0000 (---------------) + I takasaki 0x002ba308, // n0x0db4 c0x0000 (---------------) + I takayama 0x002d0048, // n0x0db5 c0x0000 (---------------) + I tamamura 0x0031d1cb, // n0x0db6 c0x0000 (---------------) + I tatebayashi 0x00287747, // n0x0db7 c0x0000 (---------------) + I tomioka 0x002f4949, // n0x0db8 c0x0000 (---------------) + I tsukiyono 0x0025fe88, // n0x0db9 c0x0000 (---------------) + I tsumagoi 0x00375244, // n0x0dba c0x0000 (---------------) + I ueno 0x002c2b08, // n0x0dbb c0x0000 (---------------) + I yoshioka 0x00285789, // n0x0dbc c0x0000 (---------------) + I asaminami 0x002a6a85, // n0x0dbd c0x0000 (---------------) + I daiwa 0x0024e1c7, // n0x0dbe c0x0000 (---------------) + I etajima 0x002b7345, // n0x0dbf c0x0000 (---------------) + I fuchu 0x00279148, // n0x0dc0 c0x0000 (---------------) + I fukuyama 0x002884cb, // n0x0dc1 c0x0000 (---------------) + I hatsukaichi 0x0028d210, // n0x0dc2 c0x0000 (---------------) + I higashihiroshima 0x002a1c05, // n0x0dc3 c0x0000 (---------------) + I hongo 0x0021618c, // n0x0dc4 c0x0000 (---------------) + I jinsekikogen 0x00224745, // n0x0dc5 c0x0000 (---------------) + I kaita 0x00275e83, // n0x0dc6 c0x0000 (---------------) + I kui 0x0027d286, // n0x0dc7 c0x0000 (---------------) + I kumano 0x002b1dc4, // n0x0dc8 c0x0000 (---------------) + I kure 0x00206446, // n0x0dc9 c0x0000 (---------------) + I mihara 0x00295807, // n0x0dca c0x0000 (---------------) + I miyoshi 0x00211d84, // n0x0dcb c0x0000 (---------------) + I naka 0x0026b308, // n0x0dcc c0x0000 (---------------) + I onomichi 0x00337ecd, // n0x0dcd c0x0000 (---------------) + I osakikamijima 0x002d22c5, // n0x0dce c0x0000 (---------------) + I otake 0x0023eb84, // n0x0dcf c0x0000 (---------------) + I saka 0x00221fc4, // n0x0dd0 c0x0000 (---------------) + I sera 0x0026d389, // n0x0dd1 c0x0000 (---------------) + I seranishi 0x00273608, // n0x0dd2 c0x0000 (---------------) + I shinichi 0x00305187, // n0x0dd3 c0x0000 (---------------) + I shobara 0x002ba6c8, // n0x0dd4 c0x0000 (---------------) + I takehara 0x00279dc8, // n0x0dd5 c0x0000 (---------------) + I abashiri 0x00272fc5, // n0x0dd6 c0x0000 (---------------) + I abira 0x003a2747, // n0x0dd7 c0x0000 (---------------) + I aibetsu 0x00272f47, // n0x0dd8 c0x0000 (---------------) + I akabira 0x002ff747, // n0x0dd9 c0x0000 (---------------) + I akkeshi 0x002b9ac9, // n0x0dda c0x0000 (---------------) + I asahikawa 0x00233a49, // n0x0ddb c0x0000 (---------------) + I ashibetsu 0x0023e146, // n0x0ddc c0x0000 (---------------) + I ashoro 0x002add06, // n0x0ddd c0x0000 (---------------) + I assabu 0x0025fe46, // n0x0dde c0x0000 (---------------) + I atsuma 0x00262005, // n0x0ddf c0x0000 (---------------) + I bibai 0x00272744, // n0x0de0 c0x0000 (---------------) + I biei 0x00200b06, // n0x0de1 c0x0000 (---------------) + I bifuka 0x00200e86, // n0x0de2 c0x0000 (---------------) + I bihoro 0x00273008, // n0x0de3 c0x0000 (---------------) + I biratori 0x002a44cb, // n0x0de4 c0x0000 (---------------) + I chippubetsu 0x002a8687, // n0x0de5 c0x0000 (---------------) + I chitose 0x0020b444, // n0x0de6 c0x0000 (---------------) + I date 0x0033bf46, // n0x0de7 c0x0000 (---------------) + I ebetsu 0x00276647, // n0x0de8 c0x0000 (---------------) + I embetsu 0x002ea945, // n0x0de9 c0x0000 (---------------) + I eniwa 0x0039acc5, // n0x0dea c0x0000 (---------------) + I erimo 0x002013c4, // n0x0deb c0x0000 (---------------) + I esan 0x002339c6, // n0x0dec c0x0000 (---------------) + I esashi 0x00200b88, // n0x0ded c0x0000 (---------------) + I fukagawa 0x003368c9, // n0x0dee c0x0000 (---------------) + I fukushima 0x00241b86, // n0x0def c0x0000 (---------------) + I furano 0x0027edc8, // n0x0df0 c0x0000 (---------------) + I furubira 0x00366c86, // n0x0df1 c0x0000 (---------------) + I haboro 0x00322a08, // n0x0df2 c0x0000 (---------------) + I hakodate 0x0029384c, // n0x0df3 c0x0000 (---------------) + I hamatonbetsu 0x00272e86, // n0x0df4 c0x0000 (---------------) + I hidaka 0x0028e3cd, // n0x0df5 c0x0000 (---------------) + I higashikagura 0x0028e84b, // n0x0df6 c0x0000 (---------------) + I higashikawa 0x00357e45, // n0x0df7 c0x0000 (---------------) + I hiroo 0x00202447, // n0x0df8 c0x0000 (---------------) + I hokuryu 0x00333346, // n0x0df9 c0x0000 (---------------) + I hokuto 0x002e0a08, // n0x0dfa c0x0000 (---------------) + I honbetsu 0x0023e1c9, // n0x0dfb c0x0000 (---------------) + I horokanai 0x002b8a08, // n0x0dfc c0x0000 (---------------) + I horonobe 0x00201785, // n0x0dfd c0x0000 (---------------) + I ikeda 0x002f2307, // n0x0dfe c0x0000 (---------------) + I imakane 0x00278508, // n0x0dff c0x0000 (---------------) + I ishikari 0x002fe849, // n0x0e00 c0x0000 (---------------) + I iwamizawa 0x00232f06, // n0x0e01 c0x0000 (---------------) + I iwanai 0x00241a8a, // n0x0e02 c0x0000 (---------------) + I kamifurano 0x002e0788, // n0x0e03 c0x0000 (---------------) + I kamikawa 0x002b884b, // n0x0e04 c0x0000 (---------------) + I kamishihoro 0x002812cc, // n0x0e05 c0x0000 (---------------) + I kamisunagawa 0x00247348, // n0x0e06 c0x0000 (---------------) + I kamoenai 0x00274586, // n0x0e07 c0x0000 (---------------) + I kayabe 0x003a3888, // n0x0e08 c0x0000 (---------------) + I kembuchi 0x00205487, // n0x0e09 c0x0000 (---------------) + I kikonai 0x00233cc9, // n0x0e0a c0x0000 (---------------) + I kimobetsu 0x002098cd, // n0x0e0b c0x0000 (---------------) + I kitahiroshima 0x00296946, // n0x0e0c c0x0000 (---------------) + I kitami 0x002a41c8, // n0x0e0d c0x0000 (---------------) + I kiyosato 0x00352ec9, // n0x0e0e c0x0000 (---------------) + I koshimizu 0x002aff88, // n0x0e0f c0x0000 (---------------) + I kunneppu 0x0027bec8, // n0x0e10 c0x0000 (---------------) + I kuriyama 0x002b324c, // n0x0e11 c0x0000 (---------------) + I kuromatsunai 0x002b43c7, // n0x0e12 c0x0000 (---------------) + I kushiro 0x002b5087, // n0x0e13 c0x0000 (---------------) + I kutchan 0x002b9905, // n0x0e14 c0x0000 (---------------) + I kyowa 0x00244387, // n0x0e15 c0x0000 (---------------) + I mashike 0x002ab248, // n0x0e16 c0x0000 (---------------) + I matsumae 0x0037b186, // n0x0e17 c0x0000 (---------------) + I mikasa 0x0024460c, // n0x0e18 c0x0000 (---------------) + I minamifurano 0x002dcdc8, // n0x0e19 c0x0000 (---------------) + I mombetsu 0x002c3e08, // n0x0e1a c0x0000 (---------------) + I moseushi 0x0025c686, // n0x0e1b c0x0000 (---------------) + I mukawa 0x00390287, // n0x0e1c c0x0000 (---------------) + I muroran 0x0023e344, // n0x0e1d c0x0000 (---------------) + I naie 0x002a7088, // n0x0e1e c0x0000 (---------------) + I nakagawa 0x0027da0c, // n0x0e1f c0x0000 (---------------) + I nakasatsunai 0x00213a4c, // n0x0e20 c0x0000 (---------------) + I nakatombetsu 0x00222305, // n0x0e21 c0x0000 (---------------) + I nanae 0x00383c87, // n0x0e22 c0x0000 (---------------) + I nanporo 0x00313786, // n0x0e23 c0x0000 (---------------) + I nayoro 0x00390206, // n0x0e24 c0x0000 (---------------) + I nemuro 0x0028f1c8, // n0x0e25 c0x0000 (---------------) + I niikappu 0x00201fc4, // n0x0e26 c0x0000 (---------------) + I niki 0x0022498b, // n0x0e27 c0x0000 (---------------) + I nishiokoppe 0x0031a58b, // n0x0e28 c0x0000 (---------------) + I noboribetsu 0x002aec06, // n0x0e29 c0x0000 (---------------) + I numata 0x00337d47, // n0x0e2a c0x0000 (---------------) + I obihiro 0x00336d85, // n0x0e2b c0x0000 (---------------) + I obira 0x00268245, // n0x0e2c c0x0000 (---------------) + I oketo 0x00224ac6, // n0x0e2d c0x0000 (---------------) + I okoppe 0x0026cf45, // n0x0e2e c0x0000 (---------------) + I otaru 0x002b92c5, // n0x0e2f c0x0000 (---------------) + I otobe 0x0039e0c7, // n0x0e30 c0x0000 (---------------) + I otofuke 0x00271649, // n0x0e31 c0x0000 (---------------) + I otoineppu 0x002debc4, // n0x0e32 c0x0000 (---------------) + I oumu 0x0026ffc5, // n0x0e33 c0x0000 (---------------) + I ozora 0x002d0405, // n0x0e34 c0x0000 (---------------) + I pippu 0x0027c548, // n0x0e35 c0x0000 (---------------) + I rankoshi 0x0026b145, // n0x0e36 c0x0000 (---------------) + I rebun 0x002a0889, // n0x0e37 c0x0000 (---------------) + I rikubetsu 0x0028bac7, // n0x0e38 c0x0000 (---------------) + I rishiri 0x0028bacb, // n0x0e39 c0x0000 (---------------) + I rishirifuji 0x00227606, // n0x0e3a c0x0000 (---------------) + I saroma 0x002241c9, // n0x0e3b c0x0000 (---------------) + I sarufutsu 0x00256548, // n0x0e3c c0x0000 (---------------) + I shakotan 0x0024acc5, // n0x0e3d c0x0000 (---------------) + I shari 0x002ff848, // n0x0e3e c0x0000 (---------------) + I shibecha 0x00233a88, // n0x0e3f c0x0000 (---------------) + I shibetsu 0x0020df87, // n0x0e40 c0x0000 (---------------) + I shikabe 0x0026d787, // n0x0e41 c0x0000 (---------------) + I shikaoi 0x00279549, // n0x0e42 c0x0000 (---------------) + I shimamaki 0x00227fc7, // n0x0e43 c0x0000 (---------------) + I shimizu 0x002528c9, // n0x0e44 c0x0000 (---------------) + I shimokawa 0x00280a8c, // n0x0e45 c0x0000 (---------------) + I shinshinotsu 0x0036fd88, // n0x0e46 c0x0000 (---------------) + I shintoku 0x0029d289, // n0x0e47 c0x0000 (---------------) + I shiranuka 0x0029ec47, // n0x0e48 c0x0000 (---------------) + I shiraoi 0x00279e89, // n0x0e49 c0x0000 (---------------) + I shiriuchi 0x00213047, // n0x0e4a c0x0000 (---------------) + I sobetsu 0x002813c8, // n0x0e4b c0x0000 (---------------) + I sunagawa 0x0027c885, // n0x0e4c c0x0000 (---------------) + I taiki 0x00317f06, // n0x0e4d c0x0000 (---------------) + I takasu 0x002b3b48, // n0x0e4e c0x0000 (---------------) + I takikawa 0x002ee648, // n0x0e4f c0x0000 (---------------) + I takinoue 0x002bb389, // n0x0e50 c0x0000 (---------------) + I teshikaga 0x002b9307, // n0x0e51 c0x0000 (---------------) + I tobetsu 0x00268bc5, // n0x0e52 c0x0000 (---------------) + I tohma 0x00204ac9, // n0x0e53 c0x0000 (---------------) + I tomakomai 0x00217fc6, // n0x0e54 c0x0000 (---------------) + I tomari 0x00287b04, // n0x0e55 c0x0000 (---------------) + I toya 0x00348cc6, // n0x0e56 c0x0000 (---------------) + I toyako 0x0025ef48, // n0x0e57 c0x0000 (---------------) + I toyotomi 0x00262a87, // n0x0e58 c0x0000 (---------------) + I toyoura 0x002a46c8, // n0x0e59 c0x0000 (---------------) + I tsubetsu 0x00218d09, // n0x0e5a c0x0000 (---------------) + I tsukigata 0x0025c407, // n0x0e5b c0x0000 (---------------) + I urakawa 0x002967c6, // n0x0e5c c0x0000 (---------------) + I urausu 0x00202504, // n0x0e5d c0x0000 (---------------) + I uryu 0x00209189, // n0x0e5e c0x0000 (---------------) + I utashinai 0x003a3d08, // n0x0e5f c0x0000 (---------------) + I wakkanai 0x0025c547, // n0x0e60 c0x0000 (---------------) + I wassamu 0x00325946, // n0x0e61 c0x0000 (---------------) + I yakumo 0x0039b306, // n0x0e62 c0x0000 (---------------) + I yoichi 0x00398584, // n0x0e63 c0x0000 (---------------) + I aioi 0x002a2006, // n0x0e64 c0x0000 (---------------) + I akashi 0x00204b83, // n0x0e65 c0x0000 (---------------) + I ako 0x003384c9, // n0x0e66 c0x0000 (---------------) + I amagasaki 0x00201bc6, // n0x0e67 c0x0000 (---------------) + I aogaki 0x002941c5, // n0x0e68 c0x0000 (---------------) + I asago 0x00296cc6, // n0x0e69 c0x0000 (---------------) + I ashiya 0x0029c8c5, // n0x0e6a c0x0000 (---------------) + I awaji 0x00278988, // n0x0e6b c0x0000 (---------------) + I fukusaki 0x00247087, // n0x0e6c c0x0000 (---------------) + I goshiki 0x0020dc06, // n0x0e6d c0x0000 (---------------) + I harima 0x00343046, // n0x0e6e c0x0000 (---------------) + I himeji 0x0032d348, // n0x0e6f c0x0000 (---------------) + I ichikawa 0x00298e07, // n0x0e70 c0x0000 (---------------) + I inagawa 0x00296985, // n0x0e71 c0x0000 (---------------) + I itami 0x002971c8, // n0x0e72 c0x0000 (---------------) + I kakogawa 0x0036fac8, // n0x0e73 c0x0000 (---------------) + I kamigori 0x002e0788, // n0x0e74 c0x0000 (---------------) + I kamikawa 0x00224605, // n0x0e75 c0x0000 (---------------) + I kasai 0x00317f86, // n0x0e76 c0x0000 (---------------) + I kasuga 0x002b8dc9, // n0x0e77 c0x0000 (---------------) + I kawanishi 0x00288044, // n0x0e78 c0x0000 (---------------) + I miki 0x0036640b, // n0x0e79 c0x0000 (---------------) + I minamiawaji 0x0021b04b, // n0x0e7a c0x0000 (---------------) + I nishinomiya 0x00228689, // n0x0e7b c0x0000 (---------------) + I nishiwaki 0x0020f703, // n0x0e7c c0x0000 (---------------) + I ono 0x00252f45, // n0x0e7d c0x0000 (---------------) + I sanda 0x00201e86, // n0x0e7e c0x0000 (---------------) + I sannan 0x00225508, // n0x0e7f c0x0000 (---------------) + I sasayama 0x002ae744, // n0x0e80 c0x0000 (---------------) + I sayo 0x002deec6, // n0x0e81 c0x0000 (---------------) + I shingu 0x002c6b49, // n0x0e82 c0x0000 (---------------) + I shinonsen 0x002b6385, // n0x0e83 c0x0000 (---------------) + I shiso 0x0039e006, // n0x0e84 c0x0000 (---------------) + I sumoto 0x00214106, // n0x0e85 c0x0000 (---------------) + I taishi 0x00216f04, // n0x0e86 c0x0000 (---------------) + I taka 0x0028ee0a, // n0x0e87 c0x0000 (---------------) + I takarazuka 0x00294108, // n0x0e88 c0x0000 (---------------) + I takasago 0x002ee646, // n0x0e89 c0x0000 (---------------) + I takino 0x0038c945, // n0x0e8a c0x0000 (---------------) + I tamba 0x0020c247, // n0x0e8b c0x0000 (---------------) + I tatsuno 0x00254807, // n0x0e8c c0x0000 (---------------) + I toyooka 0x0034d4c4, // n0x0e8d c0x0000 (---------------) + I yabu 0x0021b287, // n0x0e8e c0x0000 (---------------) + I yashiro 0x002427c4, // n0x0e8f c0x0000 (---------------) + I yoka 0x002427c6, // n0x0e90 c0x0000 (---------------) + I yokawa 0x00206403, // n0x0e91 c0x0000 (---------------) + I ami 0x002b9ac5, // n0x0e92 c0x0000 (---------------) + I asahi 0x00347f05, // n0x0e93 c0x0000 (---------------) + I bando 0x00214488, // n0x0e94 c0x0000 (---------------) + I chikusei 0x0020cc85, // n0x0e95 c0x0000 (---------------) + I daigo 0x00272bc9, // n0x0e96 c0x0000 (---------------) + I fujishiro 0x0029c147, // n0x0e97 c0x0000 (---------------) + I hitachi 0x002a6ecb, // n0x0e98 c0x0000 (---------------) + I hitachinaka 0x0029c14c, // n0x0e99 c0x0000 (---------------) + I hitachiomiya 0x0029cdca, // n0x0e9a c0x0000 (---------------) + I hitachiota 0x002bcc07, // n0x0e9b c0x0000 (---------------) + I ibaraki 0x00208583, // n0x0e9c c0x0000 (---------------) + I ina 0x00344608, // n0x0e9d c0x0000 (---------------) + I inashiki 0x002247c5, // n0x0e9e c0x0000 (---------------) + I itako 0x002b5d05, // n0x0e9f c0x0000 (---------------) + I iwama 0x00329684, // n0x0ea0 c0x0000 (---------------) + I joso 0x002812c6, // n0x0ea1 c0x0000 (---------------) + I kamisu 0x0022e446, // n0x0ea2 c0x0000 (---------------) + I kasama 0x002a2047, // n0x0ea3 c0x0000 (---------------) + I kashima 0x0020404b, // n0x0ea4 c0x0000 (---------------) + I kasumigaura 0x0021f544, // n0x0ea5 c0x0000 (---------------) + I koga 0x00371e04, // n0x0ea6 c0x0000 (---------------) + I miho 0x00260384, // n0x0ea7 c0x0000 (---------------) + I mito 0x002c2286, // n0x0ea8 c0x0000 (---------------) + I moriya 0x00211d84, // n0x0ea9 c0x0000 (---------------) + I naka 0x002ba188, // n0x0eaa c0x0000 (---------------) + I namegata 0x00329485, // n0x0eab c0x0000 (---------------) + I oarai 0x0023ecc5, // n0x0eac c0x0000 (---------------) + I ogawa 0x002cff87, // n0x0ead c0x0000 (---------------) + I omitama 0x00202549, // n0x0eae c0x0000 (---------------) + I ryugasaki 0x00348a85, // n0x0eaf c0x0000 (---------------) + I sakai 0x0036cf4a, // n0x0eb0 c0x0000 (---------------) + I sakuragawa 0x002ab4c9, // n0x0eb1 c0x0000 (---------------) + I shimodate 0x0026400a, // n0x0eb2 c0x0000 (---------------) + I shimotsuma 0x0038fdc9, // n0x0eb3 c0x0000 (---------------) + I shirosato 0x00324d84, // n0x0eb4 c0x0000 (---------------) + I sowa 0x002edac5, // n0x0eb5 c0x0000 (---------------) + I suifu 0x002a3508, // n0x0eb6 c0x0000 (---------------) + I takahagi 0x00349a4b, // n0x0eb7 c0x0000 (---------------) + I tamatsukuri 0x002efe85, // n0x0eb8 c0x0000 (---------------) + I tokai 0x0027f8c6, // n0x0eb9 c0x0000 (---------------) + I tomobe 0x00229604, // n0x0eba c0x0000 (---------------) + I tone 0x00273106, // n0x0ebb c0x0000 (---------------) + I toride 0x0025c289, // n0x0ebc c0x0000 (---------------) + I tsuchiura 0x0033c007, // n0x0ebd c0x0000 (---------------) + I tsukuba 0x003054c8, // n0x0ebe c0x0000 (---------------) + I uchihara 0x0023ea06, // n0x0ebf c0x0000 (---------------) + I ushiku 0x002dfb47, // n0x0ec0 c0x0000 (---------------) + I yachiyo 0x00279248, // n0x0ec1 c0x0000 (---------------) + I yamagata 0x0037e586, // n0x0ec2 c0x0000 (---------------) + I yawara 0x002431c4, // n0x0ec3 c0x0000 (---------------) + I yuki 0x00358787, // n0x0ec4 c0x0000 (---------------) + I anamizu 0x00332285, // n0x0ec5 c0x0000 (---------------) + I hakui 0x00340ac7, // n0x0ec6 c0x0000 (---------------) + I hakusan 0x00200c04, // n0x0ec7 c0x0000 (---------------) + I kaga 0x003332c6, // n0x0ec8 c0x0000 (---------------) + I kahoku 0x002198c8, // n0x0ec9 c0x0000 (---------------) + I kanazawa 0x0028ea08, // n0x0eca c0x0000 (---------------) + I kawakita 0x002e1e07, // n0x0ecb c0x0000 (---------------) + I komatsu 0x003395c8, // n0x0ecc c0x0000 (---------------) + I nakanoto 0x0028cac5, // n0x0ecd c0x0000 (---------------) + I nanao 0x0020f544, // n0x0ece c0x0000 (---------------) + I nomi 0x0032d248, // n0x0ecf c0x0000 (---------------) + I nonoichi 0x00254204, // n0x0ed0 c0x0000 (---------------) + I noto 0x0020df85, // n0x0ed1 c0x0000 (---------------) + I shika 0x002e2944, // n0x0ed2 c0x0000 (---------------) + I suzu 0x0034e4c7, // n0x0ed3 c0x0000 (---------------) + I tsubata 0x00282d47, // n0x0ed4 c0x0000 (---------------) + I tsurugi 0x00279fc8, // n0x0ed5 c0x0000 (---------------) + I uchinada 0x0029c906, // n0x0ed6 c0x0000 (---------------) + I wajima 0x0020cc05, // n0x0ed7 c0x0000 (---------------) + I fudai 0x002729c8, // n0x0ed8 c0x0000 (---------------) + I fujisawa 0x0024eb08, // n0x0ed9 c0x0000 (---------------) + I hanamaki 0x00298689, // n0x0eda c0x0000 (---------------) + I hiraizumi 0x0021b346, // n0x0edb c0x0000 (---------------) + I hirono 0x002301c8, // n0x0edc c0x0000 (---------------) + I ichinohe 0x0027a74a, // n0x0edd c0x0000 (---------------) + I ichinoseki 0x002ea9c8, // n0x0ede c0x0000 (---------------) + I iwaizumi 0x002d0b85, // n0x0edf c0x0000 (---------------) + I iwate 0x00222a46, // n0x0ee0 c0x0000 (---------------) + I joboji 0x00287108, // n0x0ee1 c0x0000 (---------------) + I kamaishi 0x002f23ca, // n0x0ee2 c0x0000 (---------------) + I kanegasaki 0x002fe107, // n0x0ee3 c0x0000 (---------------) + I karumai 0x00280645, // n0x0ee4 c0x0000 (---------------) + I kawai 0x0028da08, // n0x0ee5 c0x0000 (---------------) + I kitakami 0x002f5c44, // n0x0ee6 c0x0000 (---------------) + I kuji 0x00366e06, // n0x0ee7 c0x0000 (---------------) + I kunohe 0x002b5808, // n0x0ee8 c0x0000 (---------------) + I kuzumaki 0x0020f5c6, // n0x0ee9 c0x0000 (---------------) + I miyako 0x00368e08, // n0x0eea c0x0000 (---------------) + I mizusawa 0x00218587, // n0x0eeb c0x0000 (---------------) + I morioka 0x00208306, // n0x0eec c0x0000 (---------------) + I ninohe 0x00376fc4, // n0x0eed c0x0000 (---------------) + I noda 0x002b0647, // n0x0eee c0x0000 (---------------) + I ofunato 0x002eb8c4, // n0x0eef c0x0000 (---------------) + I oshu 0x0025c247, // n0x0ef0 c0x0000 (---------------) + I otsuchi 0x0039a00d, // n0x0ef1 c0x0000 (---------------) + I rikuzentakata 0x00228705, // n0x0ef2 c0x0000 (---------------) + I shiwa 0x00312dcb, // n0x0ef3 c0x0000 (---------------) + I shizukuishi 0x0029a7c6, // n0x0ef4 c0x0000 (---------------) + I sumita 0x0024c288, // n0x0ef5 c0x0000 (---------------) + I tanohata 0x0037f184, // n0x0ef6 c0x0000 (---------------) + I tono 0x0026fd86, // n0x0ef7 c0x0000 (---------------) + I yahaba 0x00274e46, // n0x0ef8 c0x0000 (---------------) + I yamada 0x003a3bc7, // n0x0ef9 c0x0000 (---------------) + I ayagawa 0x0028e08d, // n0x0efa c0x0000 (---------------) + I higashikagawa 0x002388c7, // n0x0efb c0x0000 (---------------) + I kanonji 0x0032f488, // n0x0efc c0x0000 (---------------) + I kotohira 0x00359b85, // n0x0efd c0x0000 (---------------) + I manno 0x00290088, // n0x0efe c0x0000 (---------------) + I marugame 0x002bacc6, // n0x0eff c0x0000 (---------------) + I mitoyo 0x0028cb48, // n0x0f00 c0x0000 (---------------) + I naoshima 0x00211046, // n0x0f01 c0x0000 (---------------) + I sanuki 0x003362c7, // n0x0f02 c0x0000 (---------------) + I tadotsu 0x0021c389, // n0x0f03 c0x0000 (---------------) + I takamatsu 0x0037f187, // n0x0f04 c0x0000 (---------------) + I tonosho 0x00281f08, // n0x0f05 c0x0000 (---------------) + I uchinomi 0x0026c5c5, // n0x0f06 c0x0000 (---------------) + I utazu 0x0021a9c8, // n0x0f07 c0x0000 (---------------) + I zentsuji 0x00336e85, // n0x0f08 c0x0000 (---------------) + I akune 0x0023b1c5, // n0x0f09 c0x0000 (---------------) + I amami 0x0027fc45, // n0x0f0a c0x0000 (---------------) + I hioki 0x00222583, // n0x0f0b c0x0000 (---------------) + I isa 0x0027b2c4, // n0x0f0c c0x0000 (---------------) + I isen 0x0026d905, // n0x0f0d c0x0000 (---------------) + I izumi 0x00267809, // n0x0f0e c0x0000 (---------------) + I kagoshima 0x002a90c6, // n0x0f0f c0x0000 (---------------) + I kanoya 0x002c0d08, // n0x0f10 c0x0000 (---------------) + I kawanabe 0x002f25c5, // n0x0f11 c0x0000 (---------------) + I kinko 0x00320d07, // n0x0f12 c0x0000 (---------------) + I kouyama 0x003365ca, // n0x0f13 c0x0000 (---------------) + I makurazaki 0x0039df49, // n0x0f14 c0x0000 (---------------) + I matsumoto 0x002a100a, // n0x0f15 c0x0000 (---------------) + I minamitane 0x002c7648, // n0x0f16 c0x0000 (---------------) + I nakatane 0x0021bc4c, // n0x0f17 c0x0000 (---------------) + I nishinoomote 0x0027afcd, // n0x0f18 c0x0000 (---------------) + I satsumasendai 0x002e6e83, // n0x0f19 c0x0000 (---------------) + I soo 0x00368d08, // n0x0f1a c0x0000 (---------------) + I tarumizu 0x002010c5, // n0x0f1b c0x0000 (---------------) + I yusui 0x003a3e86, // n0x0f1c c0x0000 (---------------) + I aikawa 0x00371a06, // n0x0f1d c0x0000 (---------------) + I atsugi 0x00240a05, // n0x0f1e c0x0000 (---------------) + I ayase 0x002867c9, // n0x0f1f c0x0000 (---------------) + I chigasaki 0x002d51c5, // n0x0f20 c0x0000 (---------------) + I ebina 0x002729c8, // n0x0f21 c0x0000 (---------------) + I fujisawa 0x00254106, // n0x0f22 c0x0000 (---------------) + I hadano 0x00323306, // n0x0f23 c0x0000 (---------------) + I hakone 0x00299f49, // n0x0f24 c0x0000 (---------------) + I hiratsuka 0x0037dd87, // n0x0f25 c0x0000 (---------------) + I isehara 0x002f1c86, // n0x0f26 c0x0000 (---------------) + I kaisei 0x00336548, // n0x0f27 c0x0000 (---------------) + I kamakura 0x00392ac8, // n0x0f28 c0x0000 (---------------) + I kiyokawa 0x00353547, // n0x0f29 c0x0000 (---------------) + I matsuda 0x0022820e, // n0x0f2a c0x0000 (---------------) + I minamiashigara 0x002baf05, // n0x0f2b c0x0000 (---------------) + I miura 0x002fe745, // n0x0f2c c0x0000 (---------------) + I nakai 0x0020f4c8, // n0x0f2d c0x0000 (---------------) + I ninomiya 0x0039c547, // n0x0f2e c0x0000 (---------------) + I odawara 0x00238042, // n0x0f2f c0x0000 (---------------) + I oi 0x002b2dc4, // n0x0f30 c0x0000 (---------------) + I oiso 0x0020634a, // n0x0f31 c0x0000 (---------------) + I sagamihara 0x0025c608, // n0x0f32 c0x0000 (---------------) + I samukawa 0x00276746, // n0x0f33 c0x0000 (---------------) + I tsukui 0x00290788, // n0x0f34 c0x0000 (---------------) + I yamakita 0x002881c6, // n0x0f35 c0x0000 (---------------) + I yamato 0x003193c8, // n0x0f36 c0x0000 (---------------) + I yokosuka 0x002a6788, // n0x0f37 c0x0000 (---------------) + I yugawara 0x0023b184, // n0x0f38 c0x0000 (---------------) + I zama 0x00324185, // n0x0f39 c0x0000 (---------------) + I zushi 0x006808c4, // n0x0f3a c0x0001 (---------------) ! I city 0x006808c4, // n0x0f3b c0x0001 (---------------) ! I city 0x006808c4, // n0x0f3c c0x0001 (---------------) ! I city 0x00201c83, // n0x0f3d c0x0000 (---------------) + I aki 0x0039b186, // n0x0f3e c0x0000 (---------------) + I geisei 0x00272e86, // n0x0f3f c0x0000 (---------------) + I hidaka 0x0029600c, // n0x0f40 c0x0000 (---------------) + I higashitsuno 0x00208343, // n0x0f41 c0x0000 (---------------) + I ino 0x002b6cc6, // n0x0f42 c0x0000 (---------------) + I kagami 0x00211e04, // n0x0f43 c0x0000 (---------------) + I kami 0x002bcd48, // n0x0f44 c0x0000 (---------------) + I kitagawa 0x002c6985, // n0x0f45 c0x0000 (---------------) + I kochi 0x00206446, // n0x0f46 c0x0000 (---------------) + I mihara 0x002ad4c8, // n0x0f47 c0x0000 (---------------) + I motoyama 0x002c89c6, // n0x0f48 c0x0000 (---------------) + I muroto 0x0020db86, // n0x0f49 c0x0000 (---------------) + I nahari 0x00359808, // n0x0f4a c0x0000 (---------------) + I nakamura 0x0029aa47, // n0x0f4b c0x0000 (---------------) + I nankoku 0x00227d89, // n0x0f4c c0x0000 (---------------) + I nishitosa 0x0030ba0a, // n0x0f4d c0x0000 (---------------) + I niyodogawa 0x00248bc4, // n0x0f4e c0x0000 (---------------) + I ochi 0x00242805, // n0x0f4f c0x0000 (---------------) + I okawa 0x00255785, // n0x0f50 c0x0000 (---------------) + I otoyo 0x0021bf86, // n0x0f51 c0x0000 (---------------) + I otsuki 0x0024dbc6, // n0x0f52 c0x0000 (---------------) + I sakawa 0x002a0446, // n0x0f53 c0x0000 (---------------) + I sukumo 0x002e1b06, // n0x0f54 c0x0000 (---------------) + I susaki 0x00227ec4, // n0x0f55 c0x0000 (---------------) + I tosa 0x00227ecb, // n0x0f56 c0x0000 (---------------) + I tosashimizu 0x00242744, // n0x0f57 c0x0000 (---------------) + I toyo 0x0020c2c5, // n0x0f58 c0x0000 (---------------) + I tsuno 0x002a53c5, // n0x0f59 c0x0000 (---------------) + I umaji 0x0026dc86, // n0x0f5a c0x0000 (---------------) + I yasuda 0x00398a08, // n0x0f5b c0x0000 (---------------) + I yusuhara 0x0027ae87, // n0x0f5c c0x0000 (---------------) + I amakusa 0x00305284, // n0x0f5d c0x0000 (---------------) + I arao 0x00245803, // n0x0f5e c0x0000 (---------------) + I aso 0x002f5745, // n0x0f5f c0x0000 (---------------) + I choyo 0x00243a47, // n0x0f60 c0x0000 (---------------) + I gyokuto 0x0029da09, // n0x0f61 c0x0000 (---------------) + I hitoyoshi 0x0027ad8b, // n0x0f62 c0x0000 (---------------) + I kamiamakusa 0x002a2047, // n0x0f63 c0x0000 (---------------) + I kashima 0x00214387, // n0x0f64 c0x0000 (---------------) + I kikuchi 0x002d6d84, // n0x0f65 c0x0000 (---------------) + I kosa 0x002ad3c8, // n0x0f66 c0x0000 (---------------) + I kumamoto 0x002e2087, // n0x0f67 c0x0000 (---------------) + I mashiki 0x0029dc46, // n0x0f68 c0x0000 (---------------) + I mifune 0x00242f48, // n0x0f69 c0x0000 (---------------) + I minamata 0x00282f0b, // n0x0f6a c0x0000 (---------------) + I minamioguni 0x0037b906, // n0x0f6b c0x0000 (---------------) + I nagasu 0x00212509, // n0x0f6c c0x0000 (---------------) + I nishihara 0x00283085, // n0x0f6d c0x0000 (---------------) + I oguni 0x002f66c3, // n0x0f6e c0x0000 (---------------) + I ozu 0x0039e006, // n0x0f6f c0x0000 (---------------) + I sumoto 0x00218488, // n0x0f70 c0x0000 (---------------) + I takamori 0x00211103, // n0x0f71 c0x0000 (---------------) + I uki 0x0021dcc3, // n0x0f72 c0x0000 (---------------) + I uto 0x00279246, // n0x0f73 c0x0000 (---------------) + I yamaga 0x002881c6, // n0x0f74 c0x0000 (---------------) + I yamato 0x0037a38a, // n0x0f75 c0x0000 (---------------) + I yatsushiro 0x002745c5, // n0x0f76 c0x0000 (---------------) + I ayabe 0x00274c8b, // n0x0f77 c0x0000 (---------------) + I fukuchiyama 0x00296c0b, // n0x0f78 c0x0000 (---------------) + I higashiyama 0x00238083, // n0x0f79 c0x0000 (---------------) + I ide 0x0021b683, // n0x0f7a c0x0000 (---------------) + I ine 0x002a7c04, // n0x0f7b c0x0000 (---------------) + I joyo 0x00218887, // n0x0f7c c0x0000 (---------------) + I kameoka 0x00218504, // n0x0f7d c0x0000 (---------------) + I kamo 0x00202704, // n0x0f7e c0x0000 (---------------) + I kita 0x002ebc44, // n0x0f7f c0x0000 (---------------) + I kizu 0x002eacc8, // n0x0f80 c0x0000 (---------------) + I kumiyama 0x0038c888, // n0x0f81 c0x0000 (---------------) + I kyotamba 0x002fdac9, // n0x0f82 c0x0000 (---------------) + I kyotanabe 0x0033f708, // n0x0f83 c0x0000 (---------------) + I kyotango 0x002cbc87, // n0x0f84 c0x0000 (---------------) + I maizuru 0x00228206, // n0x0f85 c0x0000 (---------------) + I minami 0x002c094f, // n0x0f86 c0x0000 (---------------) + I minamiyamashiro 0x002bb046, // n0x0f87 c0x0000 (---------------) + I miyazu 0x002c6904, // n0x0f88 c0x0000 (---------------) + I muko 0x0038c6ca, // n0x0f89 c0x0000 (---------------) + I nagaokakyo 0x00243947, // n0x0f8a c0x0000 (---------------) + I nakagyo 0x00207f46, // n0x0f8b c0x0000 (---------------) + I nantan 0x00287b49, // n0x0f8c c0x0000 (---------------) + I oyamazaki 0x002fda45, // n0x0f8d c0x0000 (---------------) + I sakyo 0x002145c5, // n0x0f8e c0x0000 (---------------) + I seika 0x002fdb86, // n0x0f8f c0x0000 (---------------) + I tanabe 0x0021ab03, // n0x0f90 c0x0000 (---------------) + I uji 0x002f5c89, // n0x0f91 c0x0000 (---------------) + I ujitawara 0x002197c6, // n0x0f92 c0x0000 (---------------) + I wazuka 0x00218ac9, // n0x0f93 c0x0000 (---------------) + I yamashina 0x003883c6, // n0x0f94 c0x0000 (---------------) + I yawata 0x002b9ac5, // n0x0f95 c0x0000 (---------------) + I asahi 0x00222705, // n0x0f96 c0x0000 (---------------) + I inabe 0x00205343, // n0x0f97 c0x0000 (---------------) + I ise 0x002189c8, // n0x0f98 c0x0000 (---------------) + I kameyama 0x00387f07, // n0x0f99 c0x0000 (---------------) + I kawagoe 0x002ea684, // n0x0f9a c0x0000 (---------------) + I kiho 0x0021c088, // n0x0f9b c0x0000 (---------------) + I kisosaki 0x0029d584, // n0x0f9c c0x0000 (---------------) + I kiwa 0x002b4246, // n0x0f9d c0x0000 (---------------) + I komono 0x0027d286, // n0x0f9e c0x0000 (---------------) + I kumano 0x0023d486, // n0x0f9f c0x0000 (---------------) + I kuwana 0x002c2409, // n0x0fa0 c0x0000 (---------------) + I matsusaka 0x002b5c85, // n0x0fa1 c0x0000 (---------------) + I meiwa 0x0029d806, // n0x0fa2 c0x0000 (---------------) + I mihama 0x00254509, // n0x0fa3 c0x0000 (---------------) + I minamiise 0x002b9f06, // n0x0fa4 c0x0000 (---------------) + I misugi 0x002c0a46, // n0x0fa5 c0x0000 (---------------) + I miyama 0x00377346, // n0x0fa6 c0x0000 (---------------) + I nabari 0x00209ac5, // n0x0fa7 c0x0000 (---------------) + I shima 0x002e2946, // n0x0fa8 c0x0000 (---------------) + I suzuka 0x003362c4, // n0x0fa9 c0x0000 (---------------) + I tado 0x0027c885, // n0x0faa c0x0000 (---------------) + I taiki 0x002b3b44, // n0x0fab c0x0000 (---------------) + I taki 0x002fab46, // n0x0fac c0x0000 (---------------) + I tamaki 0x0038ff84, // n0x0fad c0x0000 (---------------) + I toba 0x0020c2c3, // n0x0fae c0x0000 (---------------) + I tsu 0x00280305, // n0x0faf c0x0000 (---------------) + I udono 0x00233788, // n0x0fb0 c0x0000 (---------------) + I ureshino 0x00223b87, // n0x0fb1 c0x0000 (---------------) + I watarai 0x002abe49, // n0x0fb2 c0x0000 (---------------) + I yokkaichi 0x00280548, // n0x0fb3 c0x0000 (---------------) + I furukawa 0x0028fcd1, // n0x0fb4 c0x0000 (---------------) + I higashimatsushima 0x0021418a, // n0x0fb5 c0x0000 (---------------) + I ishinomaki 0x002aeb47, // n0x0fb6 c0x0000 (---------------) + I iwanuma 0x0037be86, // n0x0fb7 c0x0000 (---------------) + I kakuda 0x00211e04, // n0x0fb8 c0x0000 (---------------) + I kami 0x002b3c48, // n0x0fb9 c0x0000 (---------------) + I kawasaki 0x00289a89, // n0x0fba c0x0000 (---------------) + I kesennuma 0x002a2188, // n0x0fbb c0x0000 (---------------) + I marumori 0x0028fe8a, // n0x0fbc c0x0000 (---------------) + I matsushima 0x002a064d, // n0x0fbd c0x0000 (---------------) + I minamisanriku 0x00298846, // n0x0fbe c0x0000 (---------------) + I misato 0x00359906, // n0x0fbf c0x0000 (---------------) + I murata 0x002b0706, // n0x0fc0 c0x0000 (---------------) + I natori 0x00357887, // n0x0fc1 c0x0000 (---------------) + I ogawara 0x00298b45, // n0x0fc2 c0x0000 (---------------) + I ohira 0x0034d287, // n0x0fc3 c0x0000 (---------------) + I onagawa 0x0021c145, // n0x0fc4 c0x0000 (---------------) + I osaki 0x0028bc04, // n0x0fc5 c0x0000 (---------------) + I rifu 0x002a2846, // n0x0fc6 c0x0000 (---------------) + I semine 0x00317dc7, // n0x0fc7 c0x0000 (---------------) + I shibata 0x002f598d, // n0x0fc8 c0x0000 (---------------) + I shichikashuku 0x00287047, // n0x0fc9 c0x0000 (---------------) + I shikama 0x00260648, // n0x0fca c0x0000 (---------------) + I shiogama 0x00272cc9, // n0x0fcb c0x0000 (---------------) + I shiroishi 0x00222946, // n0x0fcc c0x0000 (---------------) + I tagajo 0x00232e85, // n0x0fcd c0x0000 (---------------) + I taiwa 0x00212904, // n0x0fce c0x0000 (---------------) + I tome 0x0025f046, // n0x0fcf c0x0000 (---------------) + I tomiya 0x0034d3c6, // n0x0fd0 c0x0000 (---------------) + I wakuya 0x0025c786, // n0x0fd1 c0x0000 (---------------) + I watari 0x00293388, // n0x0fd2 c0x0000 (---------------) + I yamamoto 0x00210a83, // n0x0fd3 c0x0000 (---------------) + I zao 0x0020fa43, // n0x0fd4 c0x0000 (---------------) + I aya 0x00319785, // n0x0fd5 c0x0000 (---------------) + I ebino 0x0022e8c6, // n0x0fd6 c0x0000 (---------------) + I gokase 0x002a6745, // n0x0fd7 c0x0000 (---------------) + I hyuga 0x0023ec08, // n0x0fd8 c0x0000 (---------------) + I kadogawa 0x002959ca, // n0x0fd9 c0x0000 (---------------) + I kawaminami 0x002bc144, // n0x0fda c0x0000 (---------------) + I kijo 0x002bcd48, // n0x0fdb c0x0000 (---------------) + I kitagawa 0x0028ec88, // n0x0fdc c0x0000 (---------------) + I kitakata 0x0026dac7, // n0x0fdd c0x0000 (---------------) + I kitaura 0x002f2689, // n0x0fde c0x0000 (---------------) + I kobayashi 0x002ad0c8, // n0x0fdf c0x0000 (---------------) + I kunitomi 0x00336947, // n0x0fe0 c0x0000 (---------------) + I kushima 0x002949c6, // n0x0fe1 c0x0000 (---------------) + I mimata 0x0020f5ca, // n0x0fe2 c0x0000 (---------------) + I miyakonojo 0x0025f0c8, // n0x0fe3 c0x0000 (---------------) + I miyazaki 0x002b8689, // n0x0fe4 c0x0000 (---------------) + I morotsuka 0x002736c8, // n0x0fe5 c0x0000 (---------------) + I nichinan 0x0021a709, // n0x0fe6 c0x0000 (---------------) + I nishimera 0x002b8b07, // n0x0fe7 c0x0000 (---------------) + I nobeoka 0x0033f5c5, // n0x0fe8 c0x0000 (---------------) + I saito 0x0029b4c6, // n0x0fe9 c0x0000 (---------------) + I shiiba 0x0037b008, // n0x0fea c0x0000 (---------------) + I shintomi 0x0024c408, // n0x0feb c0x0000 (---------------) + I takaharu 0x00218ec8, // n0x0fec c0x0000 (---------------) + I takanabe 0x00216f08, // n0x0fed c0x0000 (---------------) + I takazaki 0x0020c2c5, // n0x0fee c0x0000 (---------------) + I tsuno 0x0020af04, // n0x0fef c0x0000 (---------------) + I achi 0x00387c08, // n0x0ff0 c0x0000 (---------------) + I agematsu 0x00208044, // n0x0ff1 c0x0000 (---------------) + I anan 0x0038fbc4, // n0x0ff2 c0x0000 (---------------) + I aoki 0x002b9ac5, // n0x0ff3 c0x0000 (---------------) + I asahi 0x0028a547, // n0x0ff4 c0x0000 (---------------) + I azumino 0x00202309, // n0x0ff5 c0x0000 (---------------) + I chikuhoku 0x003a39c7, // n0x0ff6 c0x0000 (---------------) + I chikuma 0x0020af45, // n0x0ff7 c0x0000 (---------------) + I chino 0x00271246, // n0x0ff8 c0x0000 (---------------) + I fujimi 0x0032e506, // n0x0ff9 c0x0000 (---------------) + I hakuba 0x002064c4, // n0x0ffa c0x0000 (---------------) + I hara 0x0029a286, // n0x0ffb c0x0000 (---------------) + I hiraya 0x0020ca44, // n0x0ffc c0x0000 (---------------) + I iida 0x00250a46, // n0x0ffd c0x0000 (---------------) + I iijima 0x00397fc6, // n0x0ffe c0x0000 (---------------) + I iiyama 0x002154c6, // n0x0fff c0x0000 (---------------) + I iizuna 0x00201785, // n0x1000 c0x0000 (---------------) + I ikeda 0x0023eac7, // n0x1001 c0x0000 (---------------) + I ikusaka 0x00208583, // n0x1002 c0x0000 (---------------) + I ina 0x00395609, // n0x1003 c0x0000 (---------------) + I karuizawa 0x002f1988, // n0x1004 c0x0000 (---------------) + I kawakami 0x0021c084, // n0x1005 c0x0000 (---------------) + I kiso 0x003367cd, // n0x1006 c0x0000 (---------------) + I kisofukushima 0x0028eb08, // n0x1007 c0x0000 (---------------) + I kitaaiki 0x0028a308, // n0x1008 c0x0000 (---------------) + I komagane 0x002b8606, // n0x1009 c0x0000 (---------------) + I komoro 0x0021c489, // n0x100a c0x0000 (---------------) + I matsukawa 0x0039df49, // n0x100b c0x0000 (---------------) + I matsumoto 0x0025bf85, // n0x100c c0x0000 (---------------) + I miasa 0x00295aca, // n0x100d c0x0000 (---------------) + I minamiaiki 0x0026660a, // n0x100e c0x0000 (---------------) + I minamimaki 0x00278e4c, // n0x100f c0x0000 (---------------) + I minamiminowa 0x00278fc6, // n0x1010 c0x0000 (---------------) + I minowa 0x00271b06, // n0x1011 c0x0000 (---------------) + I miyada 0x002bb8c6, // n0x1012 c0x0000 (---------------) + I miyota 0x00248b89, // n0x1013 c0x0000 (---------------) + I mochizuki 0x003a40c6, // n0x1014 c0x0000 (---------------) + I nagano 0x00281446, // n0x1015 c0x0000 (---------------) + I nagawa 0x002d5286, // n0x1016 c0x0000 (---------------) + I nagiso 0x002a7088, // n0x1017 c0x0000 (---------------) + I nakagawa 0x0024e906, // n0x1018 c0x0000 (---------------) + I nakano 0x002c274b, // n0x1019 c0x0000 (---------------) + I nozawaonsen 0x0028a6c5, // n0x101a c0x0000 (---------------) + I obuse 0x0023ecc5, // n0x101b c0x0000 (---------------) + I ogawa 0x00271d85, // n0x101c c0x0000 (---------------) + I okaya 0x003a4b06, // n0x101d c0x0000 (---------------) + I omachi 0x0020f583, // n0x101e c0x0000 (---------------) + I omi 0x0023d406, // n0x101f c0x0000 (---------------) + I ookuwa 0x00286fc7, // n0x1020 c0x0000 (---------------) + I ooshika 0x002b3b05, // n0x1021 c0x0000 (---------------) + I otaki 0x0025d685, // n0x1022 c0x0000 (---------------) + I otari 0x002dbd05, // n0x1023 c0x0000 (---------------) + I sakae 0x00311b06, // n0x1024 c0x0000 (---------------) + I sakaki 0x0025c044, // n0x1025 c0x0000 (---------------) + I saku 0x00365906, // n0x1026 c0x0000 (---------------) + I sakuho 0x0025ea09, // n0x1027 c0x0000 (---------------) + I shimosuwa 0x003a498c, // n0x1028 c0x0000 (---------------) + I shinanomachi 0x0028b948, // n0x1029 c0x0000 (---------------) + I shiojiri 0x0025eb44, // n0x102a c0x0000 (---------------) + I suwa 0x002e25c6, // n0x102b c0x0000 (---------------) + I suzaka 0x0029a8c6, // n0x102c c0x0000 (---------------) + I takagi 0x00218488, // n0x102d c0x0000 (---------------) + I takamori 0x002ba308, // n0x102e c0x0000 (---------------) + I takayama 0x003a4889, // n0x102f c0x0000 (---------------) + I tateshina 0x0020c247, // n0x1030 c0x0000 (---------------) + I tatsuno 0x002997c9, // n0x1031 c0x0000 (---------------) + I togakushi 0x00268306, // n0x1032 c0x0000 (---------------) + I togura 0x00229e04, // n0x1033 c0x0000 (---------------) + I tomi 0x0020aa44, // n0x1034 c0x0000 (---------------) + I ueda 0x00281b44, // n0x1035 c0x0000 (---------------) + I wada 0x00279248, // n0x1036 c0x0000 (---------------) + I yamagata 0x0020214a, // n0x1037 c0x0000 (---------------) + I yamanouchi 0x00348a06, // n0x1038 c0x0000 (---------------) + I yasaka 0x0034f987, // n0x1039 c0x0000 (---------------) + I yasuoka 0x002f9bc7, // n0x103a c0x0000 (---------------) + I chijiwa 0x002242c5, // n0x103b c0x0000 (---------------) + I futsu 0x0027f584, // n0x103c c0x0000 (---------------) + I goto 0x00285746, // n0x103d c0x0000 (---------------) + I hasami 0x0032f586, // n0x103e c0x0000 (---------------) + I hirado 0x00202003, // n0x103f c0x0000 (---------------) + I iki 0x002f17c7, // n0x1040 c0x0000 (---------------) + I isahaya 0x00325e48, // n0x1041 c0x0000 (---------------) + I kawatana 0x0025c0ca, // n0x1042 c0x0000 (---------------) + I kuchinotsu 0x002c5988, // n0x1043 c0x0000 (---------------) + I matsuura 0x002bbfc8, // n0x1044 c0x0000 (---------------) + I nagasaki 0x0038ffc5, // n0x1045 c0x0000 (---------------) + I obama 0x00357f45, // n0x1046 c0x0000 (---------------) + I omura 0x002a8785, // n0x1047 c0x0000 (---------------) + I oseto 0x00224686, // n0x1048 c0x0000 (---------------) + I saikai 0x00373d46, // n0x1049 c0x0000 (---------------) + I sasebo 0x00212e45, // n0x104a c0x0000 (---------------) + I seihi 0x00338709, // n0x104b c0x0000 (---------------) + I shimabara 0x0027f38c, // n0x104c c0x0000 (---------------) + I shinkamigoto 0x002a8847, // n0x104d c0x0000 (---------------) + I togitsu 0x0028ff08, // n0x104e c0x0000 (---------------) + I tsushima 0x00285d85, // n0x104f c0x0000 (---------------) + I unzen 0x006808c4, // n0x1050 c0x0001 (---------------) ! I city 0x00229bc4, // n0x1051 c0x0000 (---------------) + I ando 0x00313104, // n0x1052 c0x0000 (---------------) + I gose 0x0020b086, // n0x1053 c0x0000 (---------------) + I heguri 0x0029778e, // n0x1054 c0x0000 (---------------) + I higashiyoshino 0x00214647, // n0x1055 c0x0000 (---------------) + I ikaruga 0x00357a85, // n0x1056 c0x0000 (---------------) + I ikoma 0x00287fcc, // n0x1057 c0x0000 (---------------) + I kamikitayama 0x0029d447, // n0x1058 c0x0000 (---------------) + I kanmaki 0x00317d47, // n0x1059 c0x0000 (---------------) + I kashiba 0x00318589, // n0x105a c0x0000 (---------------) + I kashihara 0x00217c09, // n0x105b c0x0000 (---------------) + I katsuragi 0x00280645, // n0x105c c0x0000 (---------------) + I kawai 0x002f1988, // n0x105d c0x0000 (---------------) + I kawakami 0x002b8dc9, // n0x105e c0x0000 (---------------) + I kawanishi 0x002d0e45, // n0x105f c0x0000 (---------------) + I koryo 0x002b3a48, // n0x1060 c0x0000 (---------------) + I kurotaki 0x002c2d06, // n0x1061 c0x0000 (---------------) + I mitsue 0x0026b586, // n0x1062 c0x0000 (---------------) + I miyake 0x002b96c4, // n0x1063 c0x0000 (---------------) + I nara 0x00319848, // n0x1064 c0x0000 (---------------) + I nosegawa 0x00222b03, // n0x1065 c0x0000 (---------------) + I oji 0x00301d04, // n0x1066 c0x0000 (---------------) + I ouda 0x002f57c5, // n0x1067 c0x0000 (---------------) + I oyodo 0x002d4207, // n0x1068 c0x0000 (---------------) + I sakurai 0x00200645, // n0x1069 c0x0000 (---------------) + I sango 0x0027a609, // n0x106a c0x0000 (---------------) + I shimoichi 0x0025540d, // n0x106b c0x0000 (---------------) + I shimokitayama 0x00277186, // n0x106c c0x0000 (---------------) + I shinjo 0x00245844, // n0x106d c0x0000 (---------------) + I soni 0x00294ac8, // n0x106e c0x0000 (---------------) + I takatori 0x0027148a, // n0x106f c0x0000 (---------------) + I tawaramoto 0x00215d87, // n0x1070 c0x0000 (---------------) + I tenkawa 0x00341b85, // n0x1071 c0x0000 (---------------) + I tenri 0x0020cc43, // n0x1072 c0x0000 (---------------) + I uda 0x00296dce, // n0x1073 c0x0000 (---------------) + I yamatokoriyama 0x002881cc, // n0x1074 c0x0000 (---------------) + I yamatotakada 0x002f01c7, // n0x1075 c0x0000 (---------------) + I yamazoe 0x00297947, // n0x1076 c0x0000 (---------------) + I yoshino 0x00200c43, // n0x1077 c0x0000 (---------------) + I aga 0x003a4105, // n0x1078 c0x0000 (---------------) + I agano 0x00313105, // n0x1079 c0x0000 (---------------) + I gosen 0x00290b48, // n0x107a c0x0000 (---------------) + I itoigawa 0x0028d849, // n0x107b c0x0000 (---------------) + I izumozaki 0x00289306, // n0x107c c0x0000 (---------------) + I joetsu 0x00218504, // n0x107d c0x0000 (---------------) + I kamo 0x002aea86, // n0x107e c0x0000 (---------------) + I kariwa 0x0039288b, // n0x107f c0x0000 (---------------) + I kashiwazaki 0x002aafcc, // n0x1080 c0x0000 (---------------) + I minamiuonuma 0x00326407, // n0x1081 c0x0000 (---------------) + I mitsuke 0x002c6645, // n0x1082 c0x0000 (---------------) + I muika 0x0036f9c8, // n0x1083 c0x0000 (---------------) + I murakami 0x00353305, // n0x1084 c0x0000 (---------------) + I myoko 0x0038c6c7, // n0x1085 c0x0000 (---------------) + I nagaoka 0x002756c7, // n0x1086 c0x0000 (---------------) + I niigata 0x00247f85, // n0x1087 c0x0000 (---------------) + I ojiya 0x0020f583, // n0x1088 c0x0000 (---------------) + I omi 0x0035bd44, // n0x1089 c0x0000 (---------------) + I sado 0x00201405, // n0x108a c0x0000 (---------------) + I sanjo 0x002deac5, // n0x108b c0x0000 (---------------) + I seiro 0x002deac6, // n0x108c c0x0000 (---------------) + I seirou 0x0025ac08, // n0x108d c0x0000 (---------------) + I sekikawa 0x00317dc7, // n0x108e c0x0000 (---------------) + I shibata 0x00371d06, // n0x108f c0x0000 (---------------) + I tagami 0x003a2646, // n0x1090 c0x0000 (---------------) + I tainai 0x0027fb86, // n0x1091 c0x0000 (---------------) + I tochio 0x002a4349, // n0x1092 c0x0000 (---------------) + I tokamachi 0x003a2847, // n0x1093 c0x0000 (---------------) + I tsubame 0x00289186, // n0x1094 c0x0000 (---------------) + I tsunan 0x002ab146, // n0x1095 c0x0000 (---------------) + I uonuma 0x00248046, // n0x1096 c0x0000 (---------------) + I yahiko 0x002a1f05, // n0x1097 c0x0000 (---------------) + I yoita 0x0020a106, // n0x1098 c0x0000 (---------------) + I yuzawa 0x0037b685, // n0x1099 c0x0000 (---------------) + I beppu 0x0026b1c8, // n0x109a c0x0000 (---------------) + I bungoono 0x00288ecb, // n0x109b c0x0000 (---------------) + I bungotakada 0x00285546, // n0x109c c0x0000 (---------------) + I hasama 0x002f9c04, // n0x109d c0x0000 (---------------) + I hiji 0x002f2189, // n0x109e c0x0000 (---------------) + I himeshima 0x0029c144, // n0x109f c0x0000 (---------------) + I hita 0x002c2c88, // n0x10a0 c0x0000 (---------------) + I kamitsue 0x00284a07, // n0x10a1 c0x0000 (---------------) + I kokonoe 0x0027bdc4, // n0x10a2 c0x0000 (---------------) + I kuju 0x002ac988, // n0x10a3 c0x0000 (---------------) + I kunisaki 0x002b4a04, // n0x10a4 c0x0000 (---------------) + I kusu 0x002a1f44, // n0x10a5 c0x0000 (---------------) + I oita 0x00281945, // n0x10a6 c0x0000 (---------------) + I saiki 0x002d2306, // n0x10a7 c0x0000 (---------------) + I taketa 0x002eac07, // n0x10a8 c0x0000 (---------------) + I tsukumi 0x002056c3, // n0x10a9 c0x0000 (---------------) + I usa 0x00296885, // n0x10aa c0x0000 (---------------) + I usuki 0x002b72c4, // n0x10ab c0x0000 (---------------) + I yufu 0x002fe786, // n0x10ac c0x0000 (---------------) + I akaiwa 0x0025c008, // n0x10ad c0x0000 (---------------) + I asakuchi 0x00325b85, // n0x10ae c0x0000 (---------------) + I bizen 0x00288b89, // n0x10af c0x0000 (---------------) + I hayashima 0x00204cc5, // n0x10b0 c0x0000 (---------------) + I ibara 0x002b6cc8, // n0x10b1 c0x0000 (---------------) + I kagamino 0x00313ec7, // n0x10b2 c0x0000 (---------------) + I kasaoka 0x00378048, // n0x10b3 c0x0000 (---------------) + I kibichuo 0x002abc87, // n0x10b4 c0x0000 (---------------) + I kumenan 0x00357289, // n0x10b5 c0x0000 (---------------) + I kurashiki 0x00227706, // n0x10b6 c0x0000 (---------------) + I maniwa 0x003128c6, // n0x10b7 c0x0000 (---------------) + I misaki 0x00257304, // n0x10b8 c0x0000 (---------------) + I nagi 0x00294905, // n0x10b9 c0x0000 (---------------) + I niimi 0x002e92cc, // n0x10ba c0x0000 (---------------) + I nishiawakura 0x00271d87, // n0x10bb c0x0000 (---------------) + I okayama 0x00272187, // n0x10bc c0x0000 (---------------) + I satosho 0x002f9a88, // n0x10bd c0x0000 (---------------) + I setouchi 0x00277186, // n0x10be c0x0000 (---------------) + I shinjo 0x00298a84, // n0x10bf c0x0000 (---------------) + I shoo 0x0031b044, // n0x10c0 c0x0000 (---------------) + I soja 0x002793c9, // n0x10c1 c0x0000 (---------------) + I takahashi 0x002bb9c6, // n0x10c2 c0x0000 (---------------) + I tamano 0x00215047, // n0x10c3 c0x0000 (---------------) + I tsuyama 0x003a3804, // n0x10c4 c0x0000 (---------------) + I wake 0x002a91c6, // n0x10c5 c0x0000 (---------------) + I yakage 0x00317945, // n0x10c6 c0x0000 (---------------) + I aguni 0x0029c447, // n0x10c7 c0x0000 (---------------) + I ginowan 0x002c26c6, // n0x10c8 c0x0000 (---------------) + I ginoza 0x00241949, // n0x10c9 c0x0000 (---------------) + I gushikami 0x00278c87, // n0x10ca c0x0000 (---------------) + I haebaru 0x0025fc07, // n0x10cb c0x0000 (---------------) + I higashi 0x00299dc6, // n0x10cc c0x0000 (---------------) + I hirara 0x0023e585, // n0x10cd c0x0000 (---------------) + I iheya 0x00276e48, // n0x10ce c0x0000 (---------------) + I ishigaki 0x00219648, // n0x10cf c0x0000 (---------------) + I ishikawa 0x00234746, // n0x10d0 c0x0000 (---------------) + I itoman 0x00325bc5, // n0x10d1 c0x0000 (---------------) + I izena 0x0031a0c6, // n0x10d2 c0x0000 (---------------) + I kadena 0x00202043, // n0x10d3 c0x0000 (---------------) + I kin 0x002909c9, // n0x10d4 c0x0000 (---------------) + I kitadaito 0x002a01ce, // n0x10d5 c0x0000 (---------------) + I kitanakagusuku 0x002ab988, // n0x10d6 c0x0000 (---------------) + I kumejima 0x0029d688, // n0x10d7 c0x0000 (---------------) + I kunigami 0x0023454b, // n0x10d8 c0x0000 (---------------) + I minamidaito 0x00288dc6, // n0x10d9 c0x0000 (---------------) + I motobu 0x0024d844, // n0x10da c0x0000 (---------------) + I nago 0x0020db84, // n0x10db c0x0000 (---------------) + I naha 0x002a02ca, // n0x10dc c0x0000 (---------------) + I nakagusuku 0x00216087, // n0x10dd c0x0000 (---------------) + I nakijin 0x00289245, // n0x10de c0x0000 (---------------) + I nanjo 0x00212509, // n0x10df c0x0000 (---------------) + I nishihara 0x002b2a45, // n0x10e0 c0x0000 (---------------) + I ogimi 0x0038fc07, // n0x10e1 c0x0000 (---------------) + I okinawa 0x002f7344, // n0x10e2 c0x0000 (---------------) + I onna 0x0031cfc7, // n0x10e3 c0x0000 (---------------) + I shimoji 0x002aed08, // n0x10e4 c0x0000 (---------------) + I taketomi 0x002d2986, // n0x10e5 c0x0000 (---------------) + I tarama 0x002eba89, // n0x10e6 c0x0000 (---------------) + I tokashiki 0x002ad1ca, // n0x10e7 c0x0000 (---------------) + I tomigusuku 0x00216006, // n0x10e8 c0x0000 (---------------) + I tonaki 0x0028e646, // n0x10e9 c0x0000 (---------------) + I urasoe 0x002a5345, // n0x10ea c0x0000 (---------------) + I uruma 0x0036e205, // n0x10eb c0x0000 (---------------) + I yaese 0x002391c7, // n0x10ec c0x0000 (---------------) + I yomitan 0x00239648, // n0x10ed c0x0000 (---------------) + I yonabaru 0x00317888, // n0x10ee c0x0000 (---------------) + I yonaguni 0x0023b186, // n0x10ef c0x0000 (---------------) + I zamami 0x00222785, // n0x10f0 c0x0000 (---------------) + I abeno 0x0024d94e, // n0x10f1 c0x0000 (---------------) + I chihayaakasaka 0x00321084, // n0x10f2 c0x0000 (---------------) + I chuo 0x002346c5, // n0x10f3 c0x0000 (---------------) + I daito 0x00270bc9, // n0x10f4 c0x0000 (---------------) + I fujiidera 0x00263208, // n0x10f5 c0x0000 (---------------) + I habikino 0x0038f086, // n0x10f6 c0x0000 (---------------) + I hannan 0x0029300c, // n0x10f7 c0x0000 (---------------) + I higashiosaka 0x002955d0, // n0x10f8 c0x0000 (---------------) + I higashisumiyoshi 0x002973cf, // n0x10f9 c0x0000 (---------------) + I higashiyodogawa 0x00298b88, // n0x10fa c0x0000 (---------------) + I hirakata 0x002bcc07, // n0x10fb c0x0000 (---------------) + I ibaraki 0x00201785, // n0x10fc c0x0000 (---------------) + I ikeda 0x0026d905, // n0x10fd c0x0000 (---------------) + I izumi 0x002eaa89, // n0x10fe c0x0000 (---------------) + I izumiotsu 0x0028dc09, // n0x10ff c0x0000 (---------------) + I izumisano 0x0021d646, // n0x1100 c0x0000 (---------------) + I kadoma 0x002eff07, // n0x1101 c0x0000 (---------------) + I kaizuka 0x00383c05, // n0x1102 c0x0000 (---------------) + I kanan 0x0031d8c9, // n0x1103 c0x0000 (---------------) + I kashiwara 0x00305bc6, // n0x1104 c0x0000 (---------------) + I katano 0x003a3f0d, // n0x1105 c0x0000 (---------------) + I kawachinagano 0x00281a09, // n0x1106 c0x0000 (---------------) + I kishiwada 0x00202704, // n0x1107 c0x0000 (---------------) + I kita 0x002ab708, // n0x1108 c0x0000 (---------------) + I kumatori 0x00387cc9, // n0x1109 c0x0000 (---------------) + I matsubara 0x00348bc6, // n0x110a c0x0000 (---------------) + I minato 0x00271345, // n0x110b c0x0000 (---------------) + I minoh 0x003128c6, // n0x110c c0x0000 (---------------) + I misaki 0x00305389, // n0x110d c0x0000 (---------------) + I moriguchi 0x002c1a08, // n0x110e c0x0000 (---------------) + I neyagawa 0x00211505, // n0x110f c0x0000 (---------------) + I nishi 0x0025ab84, // n0x1110 c0x0000 (---------------) + I nose 0x002931cb, // n0x1111 c0x0000 (---------------) + I osakasayama 0x00348a85, // n0x1112 c0x0000 (---------------) + I sakai 0x00225586, // n0x1113 c0x0000 (---------------) + I sayama 0x0027b306, // n0x1114 c0x0000 (---------------) + I sennan 0x002403c6, // n0x1115 c0x0000 (---------------) + I settsu 0x0031d3cb, // n0x1116 c0x0000 (---------------) + I shijonawate 0x00288c89, // n0x1117 c0x0000 (---------------) + I shimamoto 0x00213185, // n0x1118 c0x0000 (---------------) + I suita 0x00377e07, // n0x1119 c0x0000 (---------------) + I tadaoka 0x00214106, // n0x111a c0x0000 (---------------) + I taishi 0x0039a2c6, // n0x111b c0x0000 (---------------) + I tajiri 0x0027a4c8, // n0x111c c0x0000 (---------------) + I takaishi 0x002d2409, // n0x111d c0x0000 (---------------) + I takatsuki 0x0026040c, // n0x111e c0x0000 (---------------) + I tondabayashi 0x00243848, // n0x111f c0x0000 (---------------) + I toyonaka 0x00249206, // n0x1120 c0x0000 (---------------) + I toyono 0x0033f1c3, // n0x1121 c0x0000 (---------------) + I yao 0x0024e3c6, // n0x1122 c0x0000 (---------------) + I ariake 0x0026d5c5, // n0x1123 c0x0000 (---------------) + I arita 0x00274fc8, // n0x1124 c0x0000 (---------------) + I fukudomi 0x00222186, // n0x1125 c0x0000 (---------------) + I genkai 0x0029c688, // n0x1126 c0x0000 (---------------) + I hamatama 0x00240105, // n0x1127 c0x0000 (---------------) + I hizen 0x00273c05, // n0x1128 c0x0000 (---------------) + I imari 0x00314148, // n0x1129 c0x0000 (---------------) + I kamimine 0x002e2a47, // n0x112a c0x0000 (---------------) + I kanzaki 0x00371947, // n0x112b c0x0000 (---------------) + I karatsu 0x002a2047, // n0x112c c0x0000 (---------------) + I kashima 0x0021c208, // n0x112d c0x0000 (---------------) + I kitagata 0x00287d08, // n0x112e c0x0000 (---------------) + I kitahata 0x00244286, // n0x112f c0x0000 (---------------) + I kiyama 0x002fa987, // n0x1130 c0x0000 (---------------) + I kouhoku 0x00366907, // n0x1131 c0x0000 (---------------) + I kyuragi 0x0026d48a, // n0x1132 c0x0000 (---------------) + I nishiarita 0x0027e183, // n0x1133 c0x0000 (---------------) + I ogi 0x003a4b06, // n0x1134 c0x0000 (---------------) + I omachi 0x00202285, // n0x1135 c0x0000 (---------------) + I ouchi 0x00206344, // n0x1136 c0x0000 (---------------) + I saga 0x00272cc9, // n0x1137 c0x0000 (---------------) + I shiroishi 0x00357204, // n0x1138 c0x0000 (---------------) + I taku 0x00223c04, // n0x1139 c0x0000 (---------------) + I tara 0x0029a744, // n0x113a c0x0000 (---------------) + I tosu 0x0029794b, // n0x113b c0x0000 (---------------) + I yoshinogari 0x00387e47, // n0x113c c0x0000 (---------------) + I arakawa 0x0024db85, // n0x113d c0x0000 (---------------) + I asaka 0x0028c7c8, // n0x113e c0x0000 (---------------) + I chichibu 0x00271246, // n0x113f c0x0000 (---------------) + I fujimi 0x00271248, // n0x1140 c0x0000 (---------------) + I fujimino 0x00274506, // n0x1141 c0x0000 (---------------) + I fukaya 0x0039cf05, // n0x1142 c0x0000 (---------------) + I hanno 0x00284445, // n0x1143 c0x0000 (---------------) + I hanyu 0x002860c6, // n0x1144 c0x0000 (---------------) + I hasuda 0x00286d48, // n0x1145 c0x0000 (---------------) + I hatogaya 0x00287a88, // n0x1146 c0x0000 (---------------) + I hatoyama 0x00272e86, // n0x1147 c0x0000 (---------------) + I hidaka 0x0028c60f, // n0x1148 c0x0000 (---------------) + I higashichichibu 0x00290490, // n0x1149 c0x0000 (---------------) + I higashimatsuyama 0x00393b45, // n0x114a c0x0000 (---------------) + I honjo 0x00208583, // n0x114b c0x0000 (---------------) + I ina 0x0024aa45, // n0x114c c0x0000 (---------------) + I iruma 0x002f4888, // n0x114d c0x0000 (---------------) + I iwatsuki 0x0028db09, // n0x114e c0x0000 (---------------) + I kamiizumi 0x002e0788, // n0x114f c0x0000 (---------------) + I kamikawa 0x00348e48, // n0x1150 c0x0000 (---------------) + I kamisato 0x00203348, // n0x1151 c0x0000 (---------------) + I kasukabe 0x00387f07, // n0x1152 c0x0000 (---------------) + I kawagoe 0x00270f09, // n0x1153 c0x0000 (---------------) + I kawaguchi 0x0029c888, // n0x1154 c0x0000 (---------------) + I kawajima 0x002a7504, // n0x1155 c0x0000 (---------------) + I kazo 0x0029a5c8, // n0x1156 c0x0000 (---------------) + I kitamoto 0x0027c609, // n0x1157 c0x0000 (---------------) + I koshigaya 0x00300fc7, // n0x1158 c0x0000 (---------------) + I kounosu 0x002a0144, // n0x1159 c0x0000 (---------------) + I kuki 0x003a3a88, // n0x115a c0x0000 (---------------) + I kumagaya 0x0023e88a, // n0x115b c0x0000 (---------------) + I matsubushi 0x002cd386, // n0x115c c0x0000 (---------------) + I minano 0x00298846, // n0x115d c0x0000 (---------------) + I misato 0x0021b209, // n0x115e c0x0000 (---------------) + I miyashiro 0x00295807, // n0x115f c0x0000 (---------------) + I miyoshi 0x002c3088, // n0x1160 c0x0000 (---------------) + I moroyama 0x00206c08, // n0x1161 c0x0000 (---------------) + I nagatoro 0x003a3688, // n0x1162 c0x0000 (---------------) + I namegawa 0x0034f4c5, // n0x1163 c0x0000 (---------------) + I niiza 0x0036f1c5, // n0x1164 c0x0000 (---------------) + I ogano 0x0023ecc5, // n0x1165 c0x0000 (---------------) + I ogawa 0x003130c5, // n0x1166 c0x0000 (---------------) + I ogose 0x002e3fc7, // n0x1167 c0x0000 (---------------) + I okegawa 0x0020f585, // n0x1168 c0x0000 (---------------) + I omiya 0x002b3b05, // n0x1169 c0x0000 (---------------) + I otaki 0x0033fa86, // n0x116a c0x0000 (---------------) + I ranzan 0x002e06c7, // n0x116b c0x0000 (---------------) + I ryokami 0x00349987, // n0x116c c0x0000 (---------------) + I saitama 0x0023eb86, // n0x116d c0x0000 (---------------) + I sakado 0x002c7b85, // n0x116e c0x0000 (---------------) + I satte 0x00225586, // n0x116f c0x0000 (---------------) + I sayama 0x00247105, // n0x1170 c0x0000 (---------------) + I shiki 0x002a1588, // n0x1171 c0x0000 (---------------) + I shiraoka 0x002cfb04, // n0x1172 c0x0000 (---------------) + I soka 0x002b9f86, // n0x1173 c0x0000 (---------------) + I sugito 0x0032d644, // n0x1174 c0x0000 (---------------) + I toda 0x00221948, // n0x1175 c0x0000 (---------------) + I tokigawa 0x0037d74a, // n0x1176 c0x0000 (---------------) + I tokorozawa 0x002739cc, // n0x1177 c0x0000 (---------------) + I tsurugashima 0x00204245, // n0x1178 c0x0000 (---------------) + I urawa 0x00357946, // n0x1179 c0x0000 (---------------) + I warabi 0x002605c6, // n0x117a c0x0000 (---------------) + I yashio 0x00238186, // n0x117b c0x0000 (---------------) + I yokoze 0x00249284, // n0x117c c0x0000 (---------------) + I yono 0x00317c05, // n0x117d c0x0000 (---------------) + I yorii 0x00274347, // n0x117e c0x0000 (---------------) + I yoshida 0x00295889, // n0x117f c0x0000 (---------------) + I yoshikawa 0x0029db07, // n0x1180 c0x0000 (---------------) + I yoshimi 0x006808c4, // n0x1181 c0x0001 (---------------) ! I city 0x006808c4, // n0x1182 c0x0001 (---------------) ! I city 0x00305105, // n0x1183 c0x0000 (---------------) + I aisho 0x00237d44, // n0x1184 c0x0000 (---------------) + I gamo 0x002929ca, // n0x1185 c0x0000 (---------------) + I higashiomi 0x002710c6, // n0x1186 c0x0000 (---------------) + I hikone 0x00348dc4, // n0x1187 c0x0000 (---------------) + I koka 0x00207ec5, // n0x1188 c0x0000 (---------------) + I konan 0x00353c85, // n0x1189 c0x0000 (---------------) + I kosei 0x002f7c04, // n0x118a c0x0000 (---------------) + I koto 0x0027af47, // n0x118b c0x0000 (---------------) + I kusatsu 0x00204c47, // n0x118c c0x0000 (---------------) + I maibara 0x002c2288, // n0x118d c0x0000 (---------------) + I moriyama 0x002ff288, // n0x118e c0x0000 (---------------) + I nagahama 0x00211509, // n0x118f c0x0000 (---------------) + I nishiazai 0x00254208, // n0x1190 c0x0000 (---------------) + I notogawa 0x00292b8b, // n0x1191 c0x0000 (---------------) + I omihachiman 0x0021bf84, // n0x1192 c0x0000 (---------------) + I otsu 0x002f6085, // n0x1193 c0x0000 (---------------) + I ritto 0x00278b85, // n0x1194 c0x0000 (---------------) + I ryuoh 0x002a1fc9, // n0x1195 c0x0000 (---------------) + I takashima 0x002d2409, // n0x1196 c0x0000 (---------------) + I takatsuki 0x002f2088, // n0x1197 c0x0000 (---------------) + I torahime 0x002557c8, // n0x1198 c0x0000 (---------------) + I toyosato 0x0026dc84, // n0x1199 c0x0000 (---------------) + I yasu 0x0029a905, // n0x119a c0x0000 (---------------) + I akagi 0x00201683, // n0x119b c0x0000 (---------------) + I ama 0x0021bf45, // n0x119c c0x0000 (---------------) + I gotsu 0x0029d886, // n0x119d c0x0000 (---------------) + I hamada 0x0028d68c, // n0x119e c0x0000 (---------------) + I higashiizumo 0x002196c6, // n0x119f c0x0000 (---------------) + I hikawa 0x00247146, // n0x11a0 c0x0000 (---------------) + I hikimi 0x0028d845, // n0x11a1 c0x0000 (---------------) + I izumo 0x00311b88, // n0x11a2 c0x0000 (---------------) + I kakinoki 0x002abb06, // n0x11a3 c0x0000 (---------------) + I masuda 0x0037c006, // n0x11a4 c0x0000 (---------------) + I matsue 0x00298846, // n0x11a5 c0x0000 (---------------) + I misato 0x0022304c, // n0x11a6 c0x0000 (---------------) + I nishinoshima 0x0025c944, // n0x11a7 c0x0000 (---------------) + I ohda 0x0027fcca, // n0x11a8 c0x0000 (---------------) + I okinoshima 0x0038f248, // n0x11a9 c0x0000 (---------------) + I okuizumo 0x0028d4c7, // n0x11aa c0x0000 (---------------) + I shimane 0x002430c6, // n0x11ab c0x0000 (---------------) + I tamayu 0x002893c7, // n0x11ac c0x0000 (---------------) + I tsuwano 0x002d9385, // n0x11ad c0x0000 (---------------) + I unnan 0x00325946, // n0x11ae c0x0000 (---------------) + I yakumo 0x0034c3c6, // n0x11af c0x0000 (---------------) + I yasugi 0x00371807, // n0x11b0 c0x0000 (---------------) + I yatsuka 0x00223c44, // n0x11b1 c0x0000 (---------------) + I arai 0x0034e5c5, // n0x11b2 c0x0000 (---------------) + I atami 0x00270bc4, // n0x11b3 c0x0000 (---------------) + I fuji 0x0028bc87, // n0x11b4 c0x0000 (---------------) + I fujieda 0x00270e08, // n0x11b5 c0x0000 (---------------) + I fujikawa 0x0027198a, // n0x11b6 c0x0000 (---------------) + I fujinomiya 0x00278387, // n0x11b7 c0x0000 (---------------) + I fukuroi 0x002348c7, // n0x11b8 c0x0000 (---------------) + I gotemba 0x002bcb87, // n0x11b9 c0x0000 (---------------) + I haibara 0x00353449, // n0x11ba c0x0000 (---------------) + I hamamatsu 0x0028d68a, // n0x11bb c0x0000 (---------------) + I higashiizu 0x00227e83, // n0x11bc c0x0000 (---------------) + I ito 0x00223b45, // n0x11bd c0x0000 (---------------) + I iwata 0x00215503, // n0x11be c0x0000 (---------------) + I izu 0x002ebc89, // n0x11bf c0x0000 (---------------) + I izunokuni 0x002b3848, // n0x11c0 c0x0000 (---------------) + I kakegawa 0x002a1707, // n0x11c1 c0x0000 (---------------) + I kannami 0x002e0889, // n0x11c2 c0x0000 (---------------) + I kawanehon 0x00219746, // n0x11c3 c0x0000 (---------------) + I kawazu 0x0039f748, // n0x11c4 c0x0000 (---------------) + I kikugawa 0x002d6d85, // n0x11c5 c0x0000 (---------------) + I kosai 0x0024ec0a, // n0x11c6 c0x0000 (---------------) + I makinohara 0x002c9489, // n0x11c7 c0x0000 (---------------) + I matsuzaki 0x002600c9, // n0x11c8 c0x0000 (---------------) + I minamiizu 0x0039de07, // n0x11c9 c0x0000 (---------------) + I mishima 0x002a2289, // n0x11ca c0x0000 (---------------) + I morimachi 0x002153c8, // n0x11cb c0x0000 (---------------) + I nishiizu 0x002e2746, // n0x11cc c0x0000 (---------------) + I numazu 0x00357b08, // n0x11cd c0x0000 (---------------) + I omaezaki 0x00210bc7, // n0x11ce c0x0000 (---------------) + I shimada 0x00227fc7, // n0x11cf c0x0000 (---------------) + I shimizu 0x002ab4c7, // n0x11d0 c0x0000 (---------------) + I shimoda 0x002a8f48, // n0x11d1 c0x0000 (---------------) + I shizuoka 0x002e2446, // n0x11d2 c0x0000 (---------------) + I susono 0x0023e645, // n0x11d3 c0x0000 (---------------) + I yaizu 0x00274347, // n0x11d4 c0x0000 (---------------) + I yoshida 0x0028e148, // n0x11d5 c0x0000 (---------------) + I ashikaga 0x003414c4, // n0x11d6 c0x0000 (---------------) + I bato 0x0027b6c4, // n0x11d7 c0x0000 (---------------) + I haga 0x002f1b87, // n0x11d8 c0x0000 (---------------) + I ichikai 0x002a6b07, // n0x11d9 c0x0000 (---------------) + I iwafune 0x002b8c4a, // n0x11da c0x0000 (---------------) + I kaminokawa 0x002e26c6, // n0x11db c0x0000 (---------------) + I kanuma 0x002f004a, // n0x11dc c0x0000 (---------------) + I karasuyama 0x002b2d07, // n0x11dd c0x0000 (---------------) + I kuroiso 0x00320e47, // n0x11de c0x0000 (---------------) + I mashiko 0x0023b284, // n0x11df c0x0000 (---------------) + I mibu 0x00252984, // n0x11e0 c0x0000 (---------------) + I moka 0x00264e06, // n0x11e1 c0x0000 (---------------) + I motegi 0x00339884, // n0x11e2 c0x0000 (---------------) + I nasu 0x0033988c, // n0x11e3 c0x0000 (---------------) + I nasushiobara 0x00202d05, // n0x11e4 c0x0000 (---------------) + I nikko 0x00216d49, // n0x11e5 c0x0000 (---------------) + I nishikata 0x0027e144, // n0x11e6 c0x0000 (---------------) + I nogi 0x00298b45, // n0x11e7 c0x0000 (---------------) + I ohira 0x00271408, // n0x11e8 c0x0000 (---------------) + I ohtawara 0x00254c85, // n0x11e9 c0x0000 (---------------) + I oyama 0x002d4206, // n0x11ea c0x0000 (---------------) + I sakura 0x0020b884, // n0x11eb c0x0000 (---------------) + I sano 0x002613ca, // n0x11ec c0x0000 (---------------) + I shimotsuke 0x00292006, // n0x11ed c0x0000 (---------------) + I shioya 0x0025144a, // n0x11ee c0x0000 (---------------) + I takanezawa 0x00341547, // n0x11ef c0x0000 (---------------) + I tochigi 0x0022a5c5, // n0x11f0 c0x0000 (---------------) + I tsuga 0x0021ab05, // n0x11f1 c0x0000 (---------------) + I ujiie 0x0022430a, // n0x11f2 c0x0000 (---------------) + I utsunomiya 0x0029a385, // n0x11f3 c0x0000 (---------------) + I yaita 0x00298746, // n0x11f4 c0x0000 (---------------) + I aizumi 0x00208044, // n0x11f5 c0x0000 (---------------) + I anan 0x002a7d86, // n0x11f6 c0x0000 (---------------) + I ichiba 0x00239285, // n0x11f7 c0x0000 (---------------) + I itano 0x00222246, // n0x11f8 c0x0000 (---------------) + I kainan 0x002e1e0c, // n0x11f9 c0x0000 (---------------) + I komatsushima 0x002c320a, // n0x11fa c0x0000 (---------------) + I matsushige 0x00266704, // n0x11fb c0x0000 (---------------) + I mima 0x00228206, // n0x11fc c0x0000 (---------------) + I minami 0x00295807, // n0x11fd c0x0000 (---------------) + I miyoshi 0x002c5d84, // n0x11fe c0x0000 (---------------) + I mugi 0x002a7088, // n0x11ff c0x0000 (---------------) + I nakagawa 0x0037d646, // n0x1200 c0x0000 (---------------) + I naruto 0x0024d7c9, // n0x1201 c0x0000 (---------------) + I sanagochi 0x002a4c09, // n0x1202 c0x0000 (---------------) + I shishikui 0x0036fe89, // n0x1203 c0x0000 (---------------) + I tokushima 0x003665c6, // n0x1204 c0x0000 (---------------) + I wajiki 0x00210cc6, // n0x1205 c0x0000 (---------------) + I adachi 0x00357c47, // n0x1206 c0x0000 (---------------) + I akiruno 0x00338648, // n0x1207 c0x0000 (---------------) + I akishima 0x00210ac9, // n0x1208 c0x0000 (---------------) + I aogashima 0x00387e47, // n0x1209 c0x0000 (---------------) + I arakawa 0x0028c946, // n0x120a c0x0000 (---------------) + I bunkyo 0x002dfbc7, // n0x120b c0x0000 (---------------) + I chiyoda 0x002b05c5, // n0x120c c0x0000 (---------------) + I chofu 0x00321084, // n0x120d c0x0000 (---------------) + I chuo 0x00357807, // n0x120e c0x0000 (---------------) + I edogawa 0x002b7345, // n0x120f c0x0000 (---------------) + I fuchu 0x00281885, // n0x1210 c0x0000 (---------------) + I fussa 0x002f3087, // n0x1211 c0x0000 (---------------) + I hachijo 0x00247e48, // n0x1212 c0x0000 (---------------) + I hachioji 0x0036f946, // n0x1213 c0x0000 (---------------) + I hamura 0x0028f4cd, // n0x1214 c0x0000 (---------------) + I higashikurume 0x00290d4f, // n0x1215 c0x0000 (---------------) + I higashimurayama 0x00296c0d, // n0x1216 c0x0000 (---------------) + I higashiyamato 0x0020af84, // n0x1217 c0x0000 (---------------) + I hino 0x00233886, // n0x1218 c0x0000 (---------------) + I hinode 0x002c9a08, // n0x1219 c0x0000 (---------------) + I hinohara 0x002d5245, // n0x121a c0x0000 (---------------) + I inagi 0x0026d648, // n0x121b c0x0000 (---------------) + I itabashi 0x0020de4a, // n0x121c c0x0000 (---------------) + I katsushika 0x00202704, // n0x121d c0x0000 (---------------) + I kita 0x002e21c6, // n0x121e c0x0000 (---------------) + I kiyose 0x00207207, // n0x121f c0x0000 (---------------) + I kodaira 0x0021f547, // n0x1220 c0x0000 (---------------) + I koganei 0x0029ab09, // n0x1221 c0x0000 (---------------) + I kokubunji 0x00357ac5, // n0x1222 c0x0000 (---------------) + I komae 0x002f7c04, // n0x1223 c0x0000 (---------------) + I koto 0x003240ca, // n0x1224 c0x0000 (---------------) + I kouzushima 0x002acc89, // n0x1225 c0x0000 (---------------) + I kunitachi 0x002a2387, // n0x1226 c0x0000 (---------------) + I machida 0x0028f786, // n0x1227 c0x0000 (---------------) + I meguro 0x00348bc6, // n0x1228 c0x0000 (---------------) + I minato 0x0029a846, // n0x1229 c0x0000 (---------------) + I mitaka 0x00358846, // n0x122a c0x0000 (---------------) + I mizuho 0x002c914f, // n0x122b c0x0000 (---------------) + I musashimurayama 0x002c98c9, // n0x122c c0x0000 (---------------) + I musashino 0x0024e906, // n0x122d c0x0000 (---------------) + I nakano 0x00248886, // n0x122e c0x0000 (---------------) + I nerima 0x00300009, // n0x122f c0x0000 (---------------) + I ogasawara 0x002faa87, // n0x1230 c0x0000 (---------------) + I okutama 0x00212943, // n0x1231 c0x0000 (---------------) + I ome 0x00209a86, // n0x1232 c0x0000 (---------------) + I oshima 0x00201503, // n0x1233 c0x0000 (---------------) + I ota 0x002408c8, // n0x1234 c0x0000 (---------------) + I setagaya 0x002dfa07, // n0x1235 c0x0000 (---------------) + I shibuya 0x00298d89, // n0x1236 c0x0000 (---------------) + I shinagawa 0x0027d108, // n0x1237 c0x0000 (---------------) + I shinjuku 0x00371a88, // n0x1238 c0x0000 (---------------) + I suginami 0x00213cc6, // n0x1239 c0x0000 (---------------) + I sumida 0x0033c709, // n0x123a c0x0000 (---------------) + I tachikawa 0x00275805, // n0x123b c0x0000 (---------------) + I taito 0x002430c4, // n0x123c c0x0000 (---------------) + I tama 0x00243b87, // n0x123d c0x0000 (---------------) + I toshima 0x00248c05, // n0x123e c0x0000 (---------------) + I chizu 0x0020af84, // n0x123f c0x0000 (---------------) + I hino 0x0024dc48, // n0x1240 c0x0000 (---------------) + I kawahara 0x00216344, // n0x1241 c0x0000 (---------------) + I koge 0x002f7c07, // n0x1242 c0x0000 (---------------) + I kotoura 0x00344046, // n0x1243 c0x0000 (---------------) + I misasa 0x002d3045, // n0x1244 c0x0000 (---------------) + I nanbu 0x002736c8, // n0x1245 c0x0000 (---------------) + I nichinan 0x00348a8b, // n0x1246 c0x0000 (---------------) + I sakaiminato 0x002ec7c7, // n0x1247 c0x0000 (---------------) + I tottori 0x00224586, // n0x1248 c0x0000 (---------------) + I wakasa 0x002bb0c4, // n0x1249 c0x0000 (---------------) + I yazu 0x003040c6, // n0x124a c0x0000 (---------------) + I yonago 0x002b9ac5, // n0x124b c0x0000 (---------------) + I asahi 0x002b7345, // n0x124c c0x0000 (---------------) + I fuchu 0x00276bc9, // n0x124d c0x0000 (---------------) + I fukumitsu 0x0027ab49, // n0x124e c0x0000 (---------------) + I funahashi 0x00228004, // n0x124f c0x0000 (---------------) + I himi 0x00228045, // n0x1250 c0x0000 (---------------) + I imizu 0x00228245, // n0x1251 c0x0000 (---------------) + I inami 0x0024ea86, // n0x1252 c0x0000 (---------------) + I johana 0x002f1a88, // n0x1253 c0x0000 (---------------) + I kamiichi 0x002b2606, // n0x1254 c0x0000 (---------------) + I kurobe 0x00325c8b, // n0x1255 c0x0000 (---------------) + I nakaniikawa 0x002f73ca, // n0x1256 c0x0000 (---------------) + I namerikawa 0x002eb9c5, // n0x1257 c0x0000 (---------------) + I nanto 0x002844c6, // n0x1258 c0x0000 (---------------) + I nyuzen 0x002ea385, // n0x1259 c0x0000 (---------------) + I oyabe 0x00213245, // n0x125a c0x0000 (---------------) + I taira 0x00287e87, // n0x125b c0x0000 (---------------) + I takaoka 0x00201548, // n0x125c c0x0000 (---------------) + I tateyama 0x00254284, // n0x125d c0x0000 (---------------) + I toga 0x0025be86, // n0x125e c0x0000 (---------------) + I tonami 0x00287b06, // n0x125f c0x0000 (---------------) + I toyama 0x00215587, // n0x1260 c0x0000 (---------------) + I unazuki 0x002f6684, // n0x1261 c0x0000 (---------------) + I uozu 0x00274e46, // n0x1262 c0x0000 (---------------) + I yamada 0x003082c5, // n0x1263 c0x0000 (---------------) + I arida 0x003082c9, // n0x1264 c0x0000 (---------------) + I aridagawa 0x00210ec4, // n0x1265 c0x0000 (---------------) + I gobo 0x0027f709, // n0x1266 c0x0000 (---------------) + I hashimoto 0x00272e86, // n0x1267 c0x0000 (---------------) + I hidaka 0x002b4488, // n0x1268 c0x0000 (---------------) + I hirogawa 0x00228245, // n0x1269 c0x0000 (---------------) + I inami 0x002f9cc5, // n0x126a c0x0000 (---------------) + I iwade 0x00222246, // n0x126b c0x0000 (---------------) + I kainan 0x00260309, // n0x126c c0x0000 (---------------) + I kamitonda 0x00217c09, // n0x126d c0x0000 (---------------) + I katsuragi 0x002471c6, // n0x126e c0x0000 (---------------) + I kimino 0x00263308, // n0x126f c0x0000 (---------------) + I kinokawa 0x00255548, // n0x1270 c0x0000 (---------------) + I kitayama 0x002ea344, // n0x1271 c0x0000 (---------------) + I koya 0x00358d44, // n0x1272 c0x0000 (---------------) + I koza 0x00358d48, // n0x1273 c0x0000 (---------------) + I kozagawa 0x0030fc88, // n0x1274 c0x0000 (---------------) + I kudoyama 0x002998c9, // n0x1275 c0x0000 (---------------) + I kushimoto 0x0029d806, // n0x1276 c0x0000 (---------------) + I mihama 0x00298846, // n0x1277 c0x0000 (---------------) + I misato 0x0030d44d, // n0x1278 c0x0000 (---------------) + I nachikatsuura 0x002deec6, // n0x1279 c0x0000 (---------------) + I shingu 0x00293709, // n0x127a c0x0000 (---------------) + I shirahama 0x003a4cc5, // n0x127b c0x0000 (---------------) + I taiji 0x002fdb86, // n0x127c c0x0000 (---------------) + I tanabe 0x0033c8c8, // n0x127d c0x0000 (---------------) + I wakayama 0x0030a445, // n0x127e c0x0000 (---------------) + I yuasa 0x00366944, // n0x127f c0x0000 (---------------) + I yura 0x002b9ac5, // n0x1280 c0x0000 (---------------) + I asahi 0x0027a1c8, // n0x1281 c0x0000 (---------------) + I funagata 0x00292789, // n0x1282 c0x0000 (---------------) + I higashine 0x00270c84, // n0x1283 c0x0000 (---------------) + I iide 0x003332c6, // n0x1284 c0x0000 (---------------) + I kahoku 0x00254b4a, // n0x1285 c0x0000 (---------------) + I kaminoyama 0x002c3a08, // n0x1286 c0x0000 (---------------) + I kaneyama 0x002b8dc9, // n0x1287 c0x0000 (---------------) + I kawanishi 0x00289c4a, // n0x1288 c0x0000 (---------------) + I mamurogawa 0x002e0806, // n0x1289 c0x0000 (---------------) + I mikawa 0x00290f08, // n0x128a c0x0000 (---------------) + I murayama 0x0038c485, // n0x128b c0x0000 (---------------) + I nagai 0x002c5808, // n0x128c c0x0000 (---------------) + I nakayama 0x002abd85, // n0x128d c0x0000 (---------------) + I nanyo 0x00219609, // n0x128e c0x0000 (---------------) + I nishikawa 0x0035d349, // n0x128f c0x0000 (---------------) + I obanazawa 0x00202e02, // n0x1290 c0x0000 (---------------) + I oe 0x00283085, // n0x1291 c0x0000 (---------------) + I oguni 0x00267f86, // n0x1292 c0x0000 (---------------) + I ohkura 0x00272dc7, // n0x1293 c0x0000 (---------------) + I oishida 0x0039a485, // n0x1294 c0x0000 (---------------) + I sagae 0x002ee546, // n0x1295 c0x0000 (---------------) + I sakata 0x0030a508, // n0x1296 c0x0000 (---------------) + I sakegawa 0x00277186, // n0x1297 c0x0000 (---------------) + I shinjo 0x002a33c9, // n0x1298 c0x0000 (---------------) + I shirataka 0x00272286, // n0x1299 c0x0000 (---------------) + I shonai 0x0027a348, // n0x129a c0x0000 (---------------) + I takahata 0x002a2a85, // n0x129b c0x0000 (---------------) + I tendo 0x00265e06, // n0x129c c0x0000 (---------------) + I tozawa 0x003363c8, // n0x129d c0x0000 (---------------) + I tsuruoka 0x00279248, // n0x129e c0x0000 (---------------) + I yamagata 0x00398048, // n0x129f c0x0000 (---------------) + I yamanobe 0x00361fc8, // n0x12a0 c0x0000 (---------------) + I yonezawa 0x0020a104, // n0x12a1 c0x0000 (---------------) + I yuza 0x00228543, // n0x12a2 c0x0000 (---------------) + I abu 0x002a3604, // n0x12a3 c0x0000 (---------------) + I hagi 0x00278586, // n0x12a4 c0x0000 (---------------) + I hikari 0x002b0604, // n0x12a5 c0x0000 (---------------) + I hofu 0x0029d5c7, // n0x12a6 c0x0000 (---------------) + I iwakuni 0x0037bf09, // n0x12a7 c0x0000 (---------------) + I kudamatsu 0x002ba8c5, // n0x12a8 c0x0000 (---------------) + I mitou 0x00206c06, // n0x12a9 c0x0000 (---------------) + I nagato 0x00209a86, // n0x12aa c0x0000 (---------------) + I oshima 0x0025aa4b, // n0x12ab c0x0000 (---------------) + I shimonoseki 0x002eb906, // n0x12ac c0x0000 (---------------) + I shunan 0x0030ff86, // n0x12ad c0x0000 (---------------) + I tabuse 0x002aef88, // n0x12ae c0x0000 (---------------) + I tokuyama 0x0025d5c6, // n0x12af c0x0000 (---------------) + I toyota 0x002a0943, // n0x12b0 c0x0000 (---------------) + I ube 0x002077c3, // n0x12b1 c0x0000 (---------------) + I yuu 0x00321084, // n0x12b2 c0x0000 (---------------) + I chuo 0x002300c5, // n0x12b3 c0x0000 (---------------) + I doshi 0x00366ac7, // n0x12b4 c0x0000 (---------------) + I fuefuki 0x00270e08, // n0x12b5 c0x0000 (---------------) + I fujikawa 0x00270e0f, // n0x12b6 c0x0000 (---------------) + I fujikawaguchiko 0x0027424b, // n0x12b7 c0x0000 (---------------) + I fujiyoshida 0x002f1888, // n0x12b8 c0x0000 (---------------) + I hayakawa 0x00333346, // n0x12b9 c0x0000 (---------------) + I hokuto 0x0032d34e, // n0x12ba c0x0000 (---------------) + I ichikawamisato 0x00222243, // n0x12bb c0x0000 (---------------) + I kai 0x00235ec4, // n0x12bc c0x0000 (---------------) + I kofu 0x002eb885, // n0x12bd c0x0000 (---------------) + I koshu 0x002f5546, // n0x12be c0x0000 (---------------) + I kosuge 0x0028584b, // n0x12bf c0x0000 (---------------) + I minami-alps 0x0028a606, // n0x12c0 c0x0000 (---------------) + I minobu 0x00211d89, // n0x12c1 c0x0000 (---------------) + I nakamichi 0x002d3045, // n0x12c2 c0x0000 (---------------) + I nanbu 0x00379488, // n0x12c3 c0x0000 (---------------) + I narusawa 0x00210288, // n0x12c4 c0x0000 (---------------) + I nirasaki 0x00217acc, // n0x12c5 c0x0000 (---------------) + I nishikatsura 0x00297986, // n0x12c6 c0x0000 (---------------) + I oshino 0x0021bf86, // n0x12c7 c0x0000 (---------------) + I otsuki 0x002aadc5, // n0x12c8 c0x0000 (---------------) + I showa 0x00281cc8, // n0x12c9 c0x0000 (---------------) + I tabayama 0x002739c5, // n0x12ca c0x0000 (---------------) + I tsuru 0x00375248, // n0x12cb c0x0000 (---------------) + I uenohara 0x0029704a, // n0x12cc c0x0000 (---------------) + I yamanakako 0x0029b349, // n0x12cd c0x0000 (---------------) + I yamanashi 0x006808c4, // n0x12ce c0x0001 (---------------) ! I city 0x2d203dc2, // n0x12cf c0x00b4 (n0x12d0-n0x12d1) o I co 0x000f4e08, // n0x12d0 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x12d1 c0x0000 (---------------) + I com 0x002325c3, // n0x12d2 c0x0000 (---------------) + I edu 0x00264783, // n0x12d3 c0x0000 (---------------) + I gov 0x00214d03, // n0x12d4 c0x0000 (---------------) + I mil 0x0021e283, // n0x12d5 c0x0000 (---------------) + I net 0x00223a43, // n0x12d6 c0x0000 (---------------) + I org 0x00325b83, // n0x12d7 c0x0000 (---------------) + I biz 0x0022d0c3, // n0x12d8 c0x0000 (---------------) + I com 0x002325c3, // n0x12d9 c0x0000 (---------------) + I edu 0x00264783, // n0x12da c0x0000 (---------------) + I gov 0x003a4f84, // n0x12db c0x0000 (---------------) + I info 0x0021e283, // n0x12dc c0x0000 (---------------) + I net 0x00223a43, // n0x12dd c0x0000 (---------------) + I org 0x0022b603, // n0x12de c0x0000 (---------------) + I ass 0x002c7fc4, // n0x12df c0x0000 (---------------) + I asso 0x0022d0c3, // n0x12e0 c0x0000 (---------------) + I com 0x00235044, // n0x12e1 c0x0000 (---------------) + I coop 0x002325c3, // n0x12e2 c0x0000 (---------------) + I edu 0x0034ec04, // n0x12e3 c0x0000 (---------------) + I gouv 0x00264783, // n0x12e4 c0x0000 (---------------) + I gov 0x0039a747, // n0x12e5 c0x0000 (---------------) + I medecin 0x00214d03, // n0x12e6 c0x0000 (---------------) + I mil 0x0020f543, // n0x12e7 c0x0000 (---------------) + I nom 0x00241c88, // n0x12e8 c0x0000 (---------------) + I notaires 0x00223a43, // n0x12e9 c0x0000 (---------------) + I org 0x002ed1cb, // n0x12ea c0x0000 (---------------) + I pharmaciens 0x002d9d03, // n0x12eb c0x0000 (---------------) + I prd 0x002416c6, // n0x12ec c0x0000 (---------------) + I presse 0x00200142, // n0x12ed c0x0000 (---------------) + I tm 0x0026af0b, // n0x12ee c0x0000 (---------------) + I veterinaire 0x002325c3, // n0x12ef c0x0000 (---------------) + I edu 0x00264783, // n0x12f0 c0x0000 (---------------) + I gov 0x0021e283, // n0x12f1 c0x0000 (---------------) + I net 0x00223a43, // n0x12f2 c0x0000 (---------------) + I org 0x0022d0c3, // n0x12f3 c0x0000 (---------------) + I com 0x002325c3, // n0x12f4 c0x0000 (---------------) + I edu 0x00264783, // n0x12f5 c0x0000 (---------------) + I gov 0x00223a43, // n0x12f6 c0x0000 (---------------) + I org 0x00225083, // n0x12f7 c0x0000 (---------------) + I rep 0x00202b83, // n0x12f8 c0x0000 (---------------) + I tra 0x00203982, // n0x12f9 c0x0000 (---------------) + I ac 0x000f4e08, // n0x12fa c0x0000 (---------------) + blogspot 0x00205685, // n0x12fb c0x0000 (---------------) + I busan 0x002fc548, // n0x12fc c0x0000 (---------------) + I chungbuk 0x0030b0c8, // n0x12fd c0x0000 (---------------) + I chungnam 0x00203dc2, // n0x12fe c0x0000 (---------------) + I co 0x00395a45, // n0x12ff c0x0000 (---------------) + I daegu 0x00325607, // n0x1300 c0x0000 (---------------) + I daejeon 0x002013c2, // n0x1301 c0x0000 (---------------) + I es 0x00211fc7, // n0x1302 c0x0000 (---------------) + I gangwon 0x00200702, // n0x1303 c0x0000 (---------------) + I go 0x0022bf47, // n0x1304 c0x0000 (---------------) + I gwangju 0x002eb689, // n0x1305 c0x0000 (---------------) + I gyeongbuk 0x0038c048, // n0x1306 c0x0000 (---------------) + I gyeonggi 0x003a3509, // n0x1307 c0x0000 (---------------) + I gyeongnam 0x00200602, // n0x1308 c0x0000 (---------------) + I hs 0x00261087, // n0x1309 c0x0000 (---------------) + I incheon 0x00246f44, // n0x130a c0x0000 (---------------) + I jeju 0x003256c7, // n0x130b c0x0000 (---------------) + I jeonbuk 0x002f72c7, // n0x130c c0x0000 (---------------) + I jeonnam 0x002b1542, // n0x130d c0x0000 (---------------) + I kg 0x00214d03, // n0x130e c0x0000 (---------------) + I mil 0x0020bbc2, // n0x130f c0x0000 (---------------) + I ms 0x00201e02, // n0x1310 c0x0000 (---------------) + I ne 0x00200282, // n0x1311 c0x0000 (---------------) + I or 0x002087c2, // n0x1312 c0x0000 (---------------) + I pe 0x00204902, // n0x1313 c0x0000 (---------------) + I re 0x00213402, // n0x1314 c0x0000 (---------------) + I sc 0x00283945, // n0x1315 c0x0000 (---------------) + I seoul 0x0024afc5, // n0x1316 c0x0000 (---------------) + I ulsan 0x0022d0c3, // n0x1317 c0x0000 (---------------) + I com 0x002325c3, // n0x1318 c0x0000 (---------------) + I edu 0x00264783, // n0x1319 c0x0000 (---------------) + I gov 0x0021e283, // n0x131a c0x0000 (---------------) + I net 0x00223a43, // n0x131b c0x0000 (---------------) + I org 0x0022d0c3, // n0x131c c0x0000 (---------------) + I com 0x002325c3, // n0x131d c0x0000 (---------------) + I edu 0x00264783, // n0x131e c0x0000 (---------------) + I gov 0x00214d03, // n0x131f c0x0000 (---------------) + I mil 0x0021e283, // n0x1320 c0x0000 (---------------) + I net 0x00223a43, // n0x1321 c0x0000 (---------------) + I org 0x00000301, // n0x1322 c0x0000 (---------------) + c 0x0022d0c3, // n0x1323 c0x0000 (---------------) + I com 0x002325c3, // n0x1324 c0x0000 (---------------) + I edu 0x00264783, // n0x1325 c0x0000 (---------------) + I gov 0x003a4f84, // n0x1326 c0x0000 (---------------) + I info 0x00267a43, // n0x1327 c0x0000 (---------------) + I int 0x0021e283, // n0x1328 c0x0000 (---------------) + I net 0x00223a43, // n0x1329 c0x0000 (---------------) + I org 0x00220503, // n0x132a c0x0000 (---------------) + I per 0x0022d0c3, // n0x132b c0x0000 (---------------) + I com 0x002325c3, // n0x132c c0x0000 (---------------) + I edu 0x00264783, // n0x132d c0x0000 (---------------) + I gov 0x0021e283, // n0x132e c0x0000 (---------------) + I net 0x00223a43, // n0x132f c0x0000 (---------------) + I org 0x00203dc2, // n0x1330 c0x0000 (---------------) + I co 0x0022d0c3, // n0x1331 c0x0000 (---------------) + I com 0x002325c3, // n0x1332 c0x0000 (---------------) + I edu 0x00264783, // n0x1333 c0x0000 (---------------) + I gov 0x0021e283, // n0x1334 c0x0000 (---------------) + I net 0x00223a43, // n0x1335 c0x0000 (---------------) + I org 0x000f4e08, // n0x1336 c0x0000 (---------------) + blogspot 0x00203982, // n0x1337 c0x0000 (---------------) + I ac 0x002b5504, // n0x1338 c0x0000 (---------------) + I assn 0x0022d0c3, // n0x1339 c0x0000 (---------------) + I com 0x002325c3, // n0x133a c0x0000 (---------------) + I edu 0x00264783, // n0x133b c0x0000 (---------------) + I gov 0x00352043, // n0x133c c0x0000 (---------------) + I grp 0x0022de05, // n0x133d c0x0000 (---------------) + I hotel 0x00267a43, // n0x133e c0x0000 (---------------) + I int 0x00314403, // n0x133f c0x0000 (---------------) + I ltd 0x0021e283, // n0x1340 c0x0000 (---------------) + I net 0x002006c3, // n0x1341 c0x0000 (---------------) + I ngo 0x00223a43, // n0x1342 c0x0000 (---------------) + I org 0x00213403, // n0x1343 c0x0000 (---------------) + I sch 0x0026e003, // n0x1344 c0x0000 (---------------) + I soc 0x002292c3, // n0x1345 c0x0000 (---------------) + I web 0x0022d0c3, // n0x1346 c0x0000 (---------------) + I com 0x002325c3, // n0x1347 c0x0000 (---------------) + I edu 0x00264783, // n0x1348 c0x0000 (---------------) + I gov 0x0021e283, // n0x1349 c0x0000 (---------------) + I net 0x00223a43, // n0x134a c0x0000 (---------------) + I org 0x00203dc2, // n0x134b c0x0000 (---------------) + I co 0x00223a43, // n0x134c c0x0000 (---------------) + I org 0x000f4e08, // n0x134d c0x0000 (---------------) + blogspot 0x00264783, // n0x134e c0x0000 (---------------) + I gov 0x000f4e08, // n0x134f c0x0000 (---------------) + blogspot 0x0024ee43, // n0x1350 c0x0000 (---------------) + I asn 0x0022d0c3, // n0x1351 c0x0000 (---------------) + I com 0x00230a84, // n0x1352 c0x0000 (---------------) + I conf 0x002325c3, // n0x1353 c0x0000 (---------------) + I edu 0x00264783, // n0x1354 c0x0000 (---------------) + I gov 0x00203782, // n0x1355 c0x0000 (---------------) + I id 0x00214d03, // n0x1356 c0x0000 (---------------) + I mil 0x0021e283, // n0x1357 c0x0000 (---------------) + I net 0x00223a43, // n0x1358 c0x0000 (---------------) + I org 0x0022d0c3, // n0x1359 c0x0000 (---------------) + I com 0x002325c3, // n0x135a c0x0000 (---------------) + I edu 0x00264783, // n0x135b c0x0000 (---------------) + I gov 0x00203782, // n0x135c c0x0000 (---------------) + I id 0x00220d43, // n0x135d c0x0000 (---------------) + I med 0x0021e283, // n0x135e c0x0000 (---------------) + I net 0x00223a43, // n0x135f c0x0000 (---------------) + I org 0x002d2f03, // n0x1360 c0x0000 (---------------) + I plc 0x00213403, // n0x1361 c0x0000 (---------------) + I sch 0x00203982, // n0x1362 c0x0000 (---------------) + I ac 0x00203dc2, // n0x1363 c0x0000 (---------------) + I co 0x00264783, // n0x1364 c0x0000 (---------------) + I gov 0x0021e283, // n0x1365 c0x0000 (---------------) + I net 0x00223a43, // n0x1366 c0x0000 (---------------) + I org 0x002416c5, // n0x1367 c0x0000 (---------------) + I press 0x002c7fc4, // n0x1368 c0x0000 (---------------) + I asso 0x00200142, // n0x1369 c0x0000 (---------------) + I tm 0x000f4e08, // n0x136a c0x0000 (---------------) + blogspot 0x00203982, // n0x136b c0x0000 (---------------) + I ac 0x00203dc2, // n0x136c c0x0000 (---------------) + I co 0x000d444b, // n0x136d c0x0000 (---------------) + diskstation 0x00101c07, // n0x136e c0x0000 (---------------) + dscloud 0x002325c3, // n0x136f c0x0000 (---------------) + I edu 0x00264783, // n0x1370 c0x0000 (---------------) + I gov 0x00143184, // n0x1371 c0x0000 (---------------) + i234 0x002441c3, // n0x1372 c0x0000 (---------------) + I its 0x00101b84, // n0x1373 c0x0000 (---------------) + myds 0x0021e283, // n0x1374 c0x0000 (---------------) + I net 0x00223a43, // n0x1375 c0x0000 (---------------) + I org 0x002da7c4, // n0x1376 c0x0000 (---------------) + I priv 0x000eb508, // n0x1377 c0x0000 (---------------) + synology 0x00203dc2, // n0x1378 c0x0000 (---------------) + I co 0x0022d0c3, // n0x1379 c0x0000 (---------------) + I com 0x002325c3, // n0x137a c0x0000 (---------------) + I edu 0x00264783, // n0x137b c0x0000 (---------------) + I gov 0x00214d03, // n0x137c c0x0000 (---------------) + I mil 0x0020f543, // n0x137d c0x0000 (---------------) + I nom 0x00223a43, // n0x137e c0x0000 (---------------) + I org 0x002d9d03, // n0x137f c0x0000 (---------------) + I prd 0x00200142, // n0x1380 c0x0000 (---------------) + I tm 0x000f4e08, // n0x1381 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x1382 c0x0000 (---------------) + I com 0x002325c3, // n0x1383 c0x0000 (---------------) + I edu 0x00264783, // n0x1384 c0x0000 (---------------) + I gov 0x003a4dc3, // n0x1385 c0x0000 (---------------) + I inf 0x0020ff84, // n0x1386 c0x0000 (---------------) + I name 0x0021e283, // n0x1387 c0x0000 (---------------) + I net 0x00223a43, // n0x1388 c0x0000 (---------------) + I org 0x0022d0c3, // n0x1389 c0x0000 (---------------) + I com 0x002325c3, // n0x138a c0x0000 (---------------) + I edu 0x0034ec04, // n0x138b c0x0000 (---------------) + I gouv 0x00264783, // n0x138c c0x0000 (---------------) + I gov 0x0021e283, // n0x138d c0x0000 (---------------) + I net 0x00223a43, // n0x138e c0x0000 (---------------) + I org 0x002416c6, // n0x138f c0x0000 (---------------) + I presse 0x002325c3, // n0x1390 c0x0000 (---------------) + I edu 0x00264783, // n0x1391 c0x0000 (---------------) + I gov 0x0016aa83, // n0x1392 c0x0000 (---------------) + nyc 0x00223a43, // n0x1393 c0x0000 (---------------) + I org 0x0022d0c3, // n0x1394 c0x0000 (---------------) + I com 0x002325c3, // n0x1395 c0x0000 (---------------) + I edu 0x00264783, // n0x1396 c0x0000 (---------------) + I gov 0x0021e283, // n0x1397 c0x0000 (---------------) + I net 0x00223a43, // n0x1398 c0x0000 (---------------) + I org 0x00101c07, // n0x1399 c0x0000 (---------------) + dscloud 0x000f4e08, // n0x139a c0x0000 (---------------) + blogspot 0x00264783, // n0x139b c0x0000 (---------------) + I gov 0x0022d0c3, // n0x139c c0x0000 (---------------) + I com 0x002325c3, // n0x139d c0x0000 (---------------) + I edu 0x00264783, // n0x139e c0x0000 (---------------) + I gov 0x0021e283, // n0x139f c0x0000 (---------------) + I net 0x00223a43, // n0x13a0 c0x0000 (---------------) + I org 0x3562d0c3, // n0x13a1 c0x00d5 (n0x13a5-n0x13a6) + I com 0x002325c3, // n0x13a2 c0x0000 (---------------) + I edu 0x0021e283, // n0x13a3 c0x0000 (---------------) + I net 0x00223a43, // n0x13a4 c0x0000 (---------------) + I org 0x000f4e08, // n0x13a5 c0x0000 (---------------) + blogspot 0x00203982, // n0x13a6 c0x0000 (---------------) + I ac 0x00203dc2, // n0x13a7 c0x0000 (---------------) + I co 0x0022d0c3, // n0x13a8 c0x0000 (---------------) + I com 0x00264783, // n0x13a9 c0x0000 (---------------) + I gov 0x0021e283, // n0x13aa c0x0000 (---------------) + I net 0x00200282, // n0x13ab c0x0000 (---------------) + I or 0x00223a43, // n0x13ac c0x0000 (---------------) + I org 0x00301a47, // n0x13ad c0x0000 (---------------) + I academy 0x0032fd8b, // n0x13ae c0x0000 (---------------) + I agriculture 0x002055c3, // n0x13af c0x0000 (---------------) + I air 0x002474c8, // n0x13b0 c0x0000 (---------------) + I airguard 0x003383c7, // n0x13b1 c0x0000 (---------------) + I alabama 0x0027e486, // n0x13b2 c0x0000 (---------------) + I alaska 0x00362bc5, // n0x13b3 c0x0000 (---------------) + I amber 0x002b1b89, // n0x13b4 c0x0000 (---------------) + I ambulance 0x00241448, // n0x13b5 c0x0000 (---------------) + I american 0x00326909, // n0x13b6 c0x0000 (---------------) + I americana 0x00326910, // n0x13b7 c0x0000 (---------------) + I americanantiques 0x00352acb, // n0x13b8 c0x0000 (---------------) + I americanart 0x002b19c9, // n0x13b9 c0x0000 (---------------) + I amsterdam 0x00205dc3, // n0x13ba c0x0000 (---------------) + I and 0x00237309, // n0x13bb c0x0000 (---------------) + I annefrank 0x00231586, // n0x13bc c0x0000 (---------------) + I anthro 0x0023158c, // n0x13bd c0x0000 (---------------) + I anthropology 0x00205748, // n0x13be c0x0000 (---------------) + I antiques 0x0039dc48, // n0x13bf c0x0000 (---------------) + I aquarium 0x0024a689, // n0x13c0 c0x0000 (---------------) + I arboretum 0x0029814e, // n0x13c1 c0x0000 (---------------) + I archaeological 0x0036c78b, // n0x13c2 c0x0000 (---------------) + I archaeology 0x002c140c, // n0x13c3 c0x0000 (---------------) + I architecture 0x00203b03, // n0x13c4 c0x0000 (---------------) + I art 0x00239fcc, // n0x13c5 c0x0000 (---------------) + I artanddesign 0x00205089, // n0x13c6 c0x0000 (---------------) + I artcenter 0x00203c87, // n0x13c7 c0x0000 (---------------) + I artdeco 0x0023250c, // n0x13c8 c0x0000 (---------------) + I arteducation 0x0038b5ca, // n0x13c9 c0x0000 (---------------) + I artgallery 0x00244d04, // n0x13ca c0x0000 (---------------) + I arts 0x0024830d, // n0x13cb c0x0000 (---------------) + I artsandcrafts 0x00239e88, // n0x13cc c0x0000 (---------------) + I asmatart 0x0038770d, // n0x13cd c0x0000 (---------------) + I assassination 0x00241f86, // n0x13ce c0x0000 (---------------) + I assisi 0x002c7fcb, // n0x13cf c0x0000 (---------------) + I association 0x0026a789, // n0x13d0 c0x0000 (---------------) + I astronomy 0x0033c5c7, // n0x13d1 c0x0000 (---------------) + I atlanta 0x003093c6, // n0x13d2 c0x0000 (---------------) + I austin 0x003146c9, // n0x13d3 c0x0000 (---------------) + I australia 0x0031e88a, // n0x13d4 c0x0000 (---------------) + I automotive 0x00351c88, // n0x13d5 c0x0000 (---------------) + I aviation 0x002d96c4, // n0x13d6 c0x0000 (---------------) + I axis 0x0026fe87, // n0x13d7 c0x0000 (---------------) + I badajoz 0x0029b5c7, // n0x13d8 c0x0000 (---------------) + I baghdad 0x003266c4, // n0x13d9 c0x0000 (---------------) + I bahn 0x002379c4, // n0x13da c0x0000 (---------------) + I bale 0x0026a009, // n0x13db c0x0000 (---------------) + I baltimore 0x002bbe09, // n0x13dc c0x0000 (---------------) + I barcelona 0x002af3c8, // n0x13dd c0x0000 (---------------) + I baseball 0x0020d585, // n0x13de c0x0000 (---------------) + I basel 0x00381705, // n0x13df c0x0000 (---------------) + I baths 0x0020a4c6, // n0x13e0 c0x0000 (---------------) + I bauern 0x002481c9, // n0x13e1 c0x0000 (---------------) + I beauxarts 0x002034cd, // n0x13e2 c0x0000 (---------------) + I beeldengeluid 0x002c0e88, // n0x13e3 c0x0000 (---------------) + I bellevue 0x0020a3c7, // n0x13e4 c0x0000 (---------------) + I bergbau 0x00362c48, // n0x13e5 c0x0000 (---------------) + I berkeley 0x0030b7c6, // n0x13e6 c0x0000 (---------------) + I berlin 0x00386c84, // n0x13e7 c0x0000 (---------------) + I bern 0x00373745, // n0x13e8 c0x0000 (---------------) + I bible 0x00201ac6, // n0x13e9 c0x0000 (---------------) + I bilbao 0x00202a04, // n0x13ea c0x0000 (---------------) + I bill 0x00204f87, // n0x13eb c0x0000 (---------------) + I birdart 0x002073ca, // n0x13ec c0x0000 (---------------) + I birthplace 0x002101c4, // n0x13ed c0x0000 (---------------) + I bonn 0x00215f46, // n0x13ee c0x0000 (---------------) + I boston 0x00217749, // n0x13ef c0x0000 (---------------) + I botanical 0x0021774f, // n0x13f0 c0x0000 (---------------) + I botanicalgarden 0x0021930d, // n0x13f1 c0x0000 (---------------) + I botanicgarden 0x00219ac6, // n0x13f2 c0x0000 (---------------) + I botany 0x0021b4d0, // n0x13f3 c0x0000 (---------------) + I brandywinevalley 0x0021b8c6, // n0x13f4 c0x0000 (---------------) + I brasil 0x0021cc07, // n0x13f5 c0x0000 (---------------) + I bristol 0x0021cf87, // n0x13f6 c0x0000 (---------------) + I british 0x0021cf8f, // n0x13f7 c0x0000 (---------------) + I britishcolumbia 0x0021dec9, // n0x13f8 c0x0000 (---------------) + I broadcast 0x00221b46, // n0x13f9 c0x0000 (---------------) + I brunel 0x00223707, // n0x13fa c0x0000 (---------------) + I brussel 0x00223708, // n0x13fb c0x0000 (---------------) + I brussels 0x00223fc9, // n0x13fc c0x0000 (---------------) + I bruxelles 0x0023b308, // n0x13fd c0x0000 (---------------) + I building 0x002d0787, // n0x13fe c0x0000 (---------------) + I burghof 0x00205683, // n0x13ff c0x0000 (---------------) + I bus 0x0022cf46, // n0x1400 c0x0000 (---------------) + I bushey 0x0034e708, // n0x1401 c0x0000 (---------------) + I cadaques 0x0029840a, // n0x1402 c0x0000 (---------------) + I california 0x00229389, // n0x1403 c0x0000 (---------------) + I cambridge 0x0020b303, // n0x1404 c0x0000 (---------------) + I can 0x00325506, // n0x1405 c0x0000 (---------------) + I canada 0x0025bcca, // n0x1406 c0x0000 (---------------) + I capebreton 0x002dc547, // n0x1407 c0x0000 (---------------) + I carrier 0x00203aca, // n0x1408 c0x0000 (---------------) + I cartoonart 0x0020c5ce, // n0x1409 c0x0000 (---------------) + I casadelamoneda 0x0021e006, // n0x140a c0x0000 (---------------) + I castle 0x00283287, // n0x140b c0x0000 (---------------) + I castres 0x002112c6, // n0x140c c0x0000 (---------------) + I celtic 0x00205146, // n0x140d c0x0000 (---------------) + I center 0x0036efcb, // n0x140e c0x0000 (---------------) + I chattanooga 0x0024594a, // n0x140f c0x0000 (---------------) + I cheltenham 0x0027044d, // n0x1410 c0x0000 (---------------) + I chesapeakebay 0x00210d87, // n0x1411 c0x0000 (---------------) + I chicago 0x0026e088, // n0x1412 c0x0000 (---------------) + I children 0x0026e089, // n0x1413 c0x0000 (---------------) + I childrens 0x0026e08f, // n0x1414 c0x0000 (---------------) + I childrensgarden 0x0039b3cc, // n0x1415 c0x0000 (---------------) + I chiropractic 0x002ae289, // n0x1416 c0x0000 (---------------) + I chocolate 0x003722ce, // n0x1417 c0x0000 (---------------) + I christiansburg 0x0039a84a, // n0x1418 c0x0000 (---------------) + I cincinnati 0x0038cd06, // n0x1419 c0x0000 (---------------) + I cinema 0x0032da06, // n0x141a c0x0000 (---------------) + I circus 0x0035518c, // n0x141b c0x0000 (---------------) + I civilisation 0x0035f80c, // n0x141c c0x0000 (---------------) + I civilization 0x00363108, // n0x141d c0x0000 (---------------) + I civilwar 0x0037f087, // n0x141e c0x0000 (---------------) + I clinton 0x002a7405, // n0x141f c0x0000 (---------------) + I clock 0x003a4384, // n0x1420 c0x0000 (---------------) + I coal 0x0037ea8e, // n0x1421 c0x0000 (---------------) + I coastaldefence 0x0031eb04, // n0x1422 c0x0000 (---------------) + I cody 0x0022aa87, // n0x1423 c0x0000 (---------------) + I coldwar 0x0025d1ca, // n0x1424 c0x0000 (---------------) + I collection 0x0022b754, // n0x1425 c0x0000 (---------------) + I colonialwilliamsburg 0x0022c98f, // n0x1426 c0x0000 (---------------) + I coloradoplateau 0x0021d148, // n0x1427 c0x0000 (---------------) + I columbia 0x0022ce08, // n0x1428 c0x0000 (---------------) + I columbus 0x0035b94d, // n0x1429 c0x0000 (---------------) + I communication 0x0035b94e, // n0x142a c0x0000 (---------------) + I communications 0x0022d0c9, // n0x142b c0x0000 (---------------) + I community 0x0022edc8, // n0x142c c0x0000 (---------------) + I computer 0x0022edcf, // n0x142d c0x0000 (---------------) + I computerhistory 0x0023220c, // n0x142e c0x0000 (---------------) + I contemporary 0x0023220f, // n0x142f c0x0000 (---------------) + I contemporaryart 0x002335c7, // n0x1430 c0x0000 (---------------) + I convent 0x0023604a, // n0x1431 c0x0000 (---------------) + I copenhagen 0x0021adcb, // n0x1432 c0x0000 (---------------) + I corporation 0x0023a808, // n0x1433 c0x0000 (---------------) + I corvette 0x0023bc07, // n0x1434 c0x0000 (---------------) + I costume 0x0032ad8d, // n0x1435 c0x0000 (---------------) + I countryestate 0x002262c6, // n0x1436 c0x0000 (---------------) + I county 0x002484c6, // n0x1437 c0x0000 (---------------) + I crafts 0x0023d289, // n0x1438 c0x0000 (---------------) + I cranbrook 0x00316048, // n0x1439 c0x0000 (---------------) + I creation 0x00242208, // n0x143a c0x0000 (---------------) + I cultural 0x0024220e, // n0x143b c0x0000 (---------------) + I culturalcenter 0x0032db87, // n0x143c c0x0000 (---------------) + I culture 0x00238485, // n0x143d c0x0000 (---------------) + I cyber 0x00243645, // n0x143e c0x0000 (---------------) + I cymru 0x0020e584, // n0x143f c0x0000 (---------------) + I dali 0x0027e746, // n0x1440 c0x0000 (---------------) + I dallas 0x002af2c8, // n0x1441 c0x0000 (---------------) + I database 0x0033a183, // n0x1442 c0x0000 (---------------) + I ddr 0x00256d0e, // n0x1443 c0x0000 (---------------) + I decorativearts 0x0032b148, // n0x1444 c0x0000 (---------------) + I delaware 0x0027320b, // n0x1445 c0x0000 (---------------) + I delmenhorst 0x0024f007, // n0x1446 c0x0000 (---------------) + I denmark 0x0026ce85, // n0x1447 c0x0000 (---------------) + I depot 0x002289c6, // n0x1448 c0x0000 (---------------) + I design 0x002a3ec7, // n0x1449 c0x0000 (---------------) + I detroit 0x002f0c88, // n0x144a c0x0000 (---------------) + I dinosaur 0x00238bc9, // n0x144b c0x0000 (---------------) + I discovery 0x00226545, // n0x144c c0x0000 (---------------) + I dolls 0x00280348, // n0x144d c0x0000 (---------------) + I donostia 0x00211a86, // n0x144e c0x0000 (---------------) + I durham 0x00369bca, // n0x144f c0x0000 (---------------) + I eastafrica 0x0037e989, // n0x1450 c0x0000 (---------------) + I eastcoast 0x002325c9, // n0x1451 c0x0000 (---------------) + I education 0x002325cb, // n0x1452 c0x0000 (---------------) + I educational 0x00286548, // n0x1453 c0x0000 (---------------) + I egyptian 0x00326589, // n0x1454 c0x0000 (---------------) + I eisenbahn 0x0020d646, // n0x1455 c0x0000 (---------------) + I elburg 0x0027ffca, // n0x1456 c0x0000 (---------------) + I elvendrell 0x00237f4a, // n0x1457 c0x0000 (---------------) + I embroidery 0x0023624c, // n0x1458 c0x0000 (---------------) + I encyclopedic 0x00390807, // n0x1459 c0x0000 (---------------) + I england 0x0038be4a, // n0x145a c0x0000 (---------------) + I entomology 0x0033554b, // n0x145b c0x0000 (---------------) + I environment 0x00335559, // n0x145c c0x0000 (---------------) + I environmentalconservation 0x0031ffc8, // n0x145d c0x0000 (---------------) + I epilepsy 0x00241745, // n0x145e c0x0000 (---------------) + I essex 0x002bd5c6, // n0x145f c0x0000 (---------------) + I estate 0x00306249, // n0x1460 c0x0000 (---------------) + I ethnology 0x00210046, // n0x1461 c0x0000 (---------------) + I exeter 0x0020f28a, // n0x1462 c0x0000 (---------------) + I exhibition 0x0036a7c6, // n0x1463 c0x0000 (---------------) + I family 0x002bd744, // n0x1464 c0x0000 (---------------) + I farm 0x002bd74d, // n0x1465 c0x0000 (---------------) + I farmequipment 0x00338c47, // n0x1466 c0x0000 (---------------) + I farmers 0x002fe2c9, // n0x1467 c0x0000 (---------------) + I farmstead 0x00361805, // n0x1468 c0x0000 (---------------) + I field 0x00361bc8, // n0x1469 c0x0000 (---------------) + I figueres 0x003746c9, // n0x146a c0x0000 (---------------) + I filatelia 0x00244544, // n0x146b c0x0000 (---------------) + I film 0x00244c07, // n0x146c c0x0000 (---------------) + I fineart 0x00244c08, // n0x146d c0x0000 (---------------) + I finearts 0x00245187, // n0x146e c0x0000 (---------------) + I finland 0x0025e848, // n0x146f c0x0000 (---------------) + I flanders 0x0024bf47, // n0x1470 c0x0000 (---------------) + I florida 0x002330c5, // n0x1471 c0x0000 (---------------) + I force 0x0025334c, // n0x1472 c0x0000 (---------------) + I fortmissoula 0x00253f09, // n0x1473 c0x0000 (---------------) + I fortworth 0x002b3eca, // n0x1474 c0x0000 (---------------) + I foundation 0x0037dc09, // n0x1475 c0x0000 (---------------) + I francaise 0x00237409, // n0x1476 c0x0000 (---------------) + I frankfurt 0x0024864c, // n0x1477 c0x0000 (---------------) + I franziskaner 0x002e048b, // n0x1478 c0x0000 (---------------) + I freemasonry 0x00255dc8, // n0x1479 c0x0000 (---------------) + I freiburg 0x00257508, // n0x147a c0x0000 (---------------) + I fribourg 0x0025a8c4, // n0x147b c0x0000 (---------------) + I frog 0x0027ba88, // n0x147c c0x0000 (---------------) + I fundacio 0x0027d409, // n0x147d c0x0000 (---------------) + I furniture 0x0038b687, // n0x147e c0x0000 (---------------) + I gallery 0x00217986, // n0x147f c0x0000 (---------------) + I garden 0x0023f607, // n0x1480 c0x0000 (---------------) + I gateway 0x00238e49, // n0x1481 c0x0000 (---------------) + I geelvinck 0x0039044b, // n0x1482 c0x0000 (---------------) + I gemological 0x00317707, // n0x1483 c0x0000 (---------------) + I geology 0x0035bf87, // n0x1484 c0x0000 (---------------) + I georgia 0x0027e1c7, // n0x1485 c0x0000 (---------------) + I giessen 0x00387684, // n0x1486 c0x0000 (---------------) + I glas 0x00387685, // n0x1487 c0x0000 (---------------) + I glass 0x002a1cc5, // n0x1488 c0x0000 (---------------) + I gorge 0x00328ecb, // n0x1489 c0x0000 (---------------) + I grandrapids 0x00388c44, // n0x148a c0x0000 (---------------) + I graz 0x002defc8, // n0x148b c0x0000 (---------------) + I guernsey 0x00280f0a, // n0x148c c0x0000 (---------------) + I halloffame 0x00211b47, // n0x148d c0x0000 (---------------) + I hamburg 0x00315447, // n0x148e c0x0000 (---------------) + I handson 0x002850d2, // n0x148f c0x0000 (---------------) + I harvestcelebration 0x00250946, // n0x1490 c0x0000 (---------------) + I hawaii 0x00366f06, // n0x1491 c0x0000 (---------------) + I health 0x003188ce, // n0x1492 c0x0000 (---------------) + I heimatunduhren 0x00251906, // n0x1493 c0x0000 (---------------) + I hellas 0x00209748, // n0x1494 c0x0000 (---------------) + I helsinki 0x0028b44f, // n0x1495 c0x0000 (---------------) + I hembygdsforbund 0x00387ac8, // n0x1496 c0x0000 (---------------) + I heritage 0x0035a948, // n0x1497 c0x0000 (---------------) + I histoire 0x0035404a, // n0x1498 c0x0000 (---------------) + I historical 0x00354051, // n0x1499 c0x0000 (---------------) + I historicalsociety 0x0029bb4e, // n0x149a c0x0000 (---------------) + I historichouses 0x0025064a, // n0x149b c0x0000 (---------------) + I historisch 0x0025064c, // n0x149c c0x0000 (---------------) + I historisches 0x0022efc7, // n0x149d c0x0000 (---------------) + I history 0x0022efd0, // n0x149e c0x0000 (---------------) + I historyofscience 0x00200f08, // n0x149f c0x0000 (---------------) + I horology 0x0029bd45, // n0x14a0 c0x0000 (---------------) + I house 0x002a49ca, // n0x14a1 c0x0000 (---------------) + I humanities 0x00202a4c, // n0x14a2 c0x0000 (---------------) + I illustration 0x0028cc8d, // n0x14a3 c0x0000 (---------------) + I imageandsound 0x0029f1c6, // n0x14a4 c0x0000 (---------------) + I indian 0x0029f1c7, // n0x14a5 c0x0000 (---------------) + I indiana 0x0029f1cc, // n0x14a6 c0x0000 (---------------) + I indianapolis 0x002e530c, // n0x14a7 c0x0000 (---------------) + I indianmarket 0x002f634c, // n0x14a8 c0x0000 (---------------) + I intelligence 0x0033254b, // n0x14a9 c0x0000 (---------------) + I interactive 0x0027ef04, // n0x14aa c0x0000 (---------------) + I iraq 0x0021b384, // n0x14ab c0x0000 (---------------) + I iron 0x0034c509, // n0x14ac c0x0000 (---------------) + I isleofman 0x002c5547, // n0x14ad c0x0000 (---------------) + I jamison 0x0036f4c9, // n0x14ae c0x0000 (---------------) + I jefferson 0x00276489, // n0x14af c0x0000 (---------------) + I jerusalem 0x0035ca47, // n0x14b0 c0x0000 (---------------) + I jewelry 0x0038b446, // n0x14b1 c0x0000 (---------------) + I jewish 0x0038b449, // n0x14b2 c0x0000 (---------------) + I jewishart 0x003951c3, // n0x14b3 c0x0000 (---------------) + I jfk 0x0027728a, // n0x14b4 c0x0000 (---------------) + I journalism 0x003a45c7, // n0x14b5 c0x0000 (---------------) + I judaica 0x0020600b, // n0x14b6 c0x0000 (---------------) + I judygarland 0x002702ca, // n0x14b7 c0x0000 (---------------) + I juedisches 0x0022c084, // n0x14b8 c0x0000 (---------------) + I juif 0x0034fac6, // n0x14b9 c0x0000 (---------------) + I karate 0x00278609, // n0x14ba c0x0000 (---------------) + I karikatur 0x00286984, // n0x14bb c0x0000 (---------------) + I kids 0x00202dca, // n0x14bc c0x0000 (---------------) + I koebenhavn 0x00224885, // n0x14bd c0x0000 (---------------) + I koeln 0x002b0dc5, // n0x14be c0x0000 (---------------) + I kunst 0x002b0dcd, // n0x14bf c0x0000 (---------------) + I kunstsammlung 0x002b110e, // n0x14c0 c0x0000 (---------------) + I kunstunddesign 0x0030ea85, // n0x14c1 c0x0000 (---------------) + I labor 0x00384146, // n0x14c2 c0x0000 (---------------) + I labour 0x002412c7, // n0x14c3 c0x0000 (---------------) + I lajolla 0x002c864a, // n0x14c4 c0x0000 (---------------) + I lancashire 0x0031ee06, // n0x14c5 c0x0000 (---------------) + I landes 0x00356f84, // n0x14c6 c0x0000 (---------------) + I lans 0x002d9b47, // n0x14c7 c0x0000 (---------------) + I larsson 0x00214bcb, // n0x14c8 c0x0000 (---------------) + I lewismiller 0x0030b887, // n0x14c9 c0x0000 (---------------) + I lincoln 0x00397e84, // n0x14ca c0x0000 (---------------) + I linz 0x002d7ac6, // n0x14cb c0x0000 (---------------) + I living 0x002d7acd, // n0x14cc c0x0000 (---------------) + I livinghistory 0x00236f8c, // n0x14cd c0x0000 (---------------) + I localhistory 0x00313c86, // n0x14ce c0x0000 (---------------) + I london 0x002c108a, // n0x14cf c0x0000 (---------------) + I losangeles 0x00224f86, // n0x14d0 c0x0000 (---------------) + I louvre 0x00292208, // n0x14d1 c0x0000 (---------------) + I loyalist 0x002afdc7, // n0x14d2 c0x0000 (---------------) + I lucerne 0x0022c50a, // n0x14d3 c0x0000 (---------------) + I luxembourg 0x00234ec6, // n0x14d4 c0x0000 (---------------) + I luzern 0x00210c83, // n0x14d5 c0x0000 (---------------) + I mad 0x00310646, // n0x14d6 c0x0000 (---------------) + I madrid 0x00200188, // n0x14d7 c0x0000 (---------------) + I mallorca 0x00292d8a, // n0x14d8 c0x0000 (---------------) + I manchester 0x0024ab07, // n0x14d9 c0x0000 (---------------) + I mansion 0x0024ab08, // n0x14da c0x0000 (---------------) + I mansions 0x00262344, // n0x14db c0x0000 (---------------) + I manx 0x00271ec7, // n0x14dc c0x0000 (---------------) + I marburg 0x00218048, // n0x14dd c0x0000 (---------------) + I maritime 0x0029ca08, // n0x14de c0x0000 (---------------) + I maritimo 0x00250b48, // n0x14df c0x0000 (---------------) + I maryland 0x0027610a, // n0x14e0 c0x0000 (---------------) + I marylhurst 0x003a15c5, // n0x14e1 c0x0000 (---------------) + I media 0x00232ac7, // n0x14e2 c0x0000 (---------------) + I medical 0x00250493, // n0x14e3 c0x0000 (---------------) + I medizinhistorisches 0x00252786, // n0x14e4 c0x0000 (---------------) + I meeres 0x00399a08, // n0x14e5 c0x0000 (---------------) + I memorial 0x00221209, // n0x14e6 c0x0000 (---------------) + I mesaverde 0x00211e88, // n0x14e7 c0x0000 (---------------) + I michigan 0x00213d4b, // n0x14e8 c0x0000 (---------------) + I midatlantic 0x002b2b08, // n0x14e9 c0x0000 (---------------) + I military 0x00214d04, // n0x14ea c0x0000 (---------------) + I mill 0x00314246, // n0x14eb c0x0000 (---------------) + I miners 0x002f6e46, // n0x14ec c0x0000 (---------------) + I mining 0x002d2149, // n0x14ed c0x0000 (---------------) + I minnesota 0x002b9d07, // n0x14ee c0x0000 (---------------) + I missile 0x00253448, // n0x14ef c0x0000 (---------------) + I missoula 0x0038f3c6, // n0x14f0 c0x0000 (---------------) + I modern 0x0022a284, // n0x14f1 c0x0000 (---------------) + I moma 0x002c2f45, // n0x14f2 c0x0000 (---------------) + I money 0x002bc9c8, // n0x14f3 c0x0000 (---------------) + I monmouth 0x002bd10a, // n0x14f4 c0x0000 (---------------) + I monticello 0x002bd3c8, // n0x14f5 c0x0000 (---------------) + I montreal 0x002c3686, // n0x14f6 c0x0000 (---------------) + I moscow 0x0029348a, // n0x14f7 c0x0000 (---------------) + I motorcycle 0x002dec48, // n0x14f8 c0x0000 (---------------) + I muenchen 0x002c5b88, // n0x14f9 c0x0000 (---------------) + I muenster 0x002c6e88, // n0x14fa c0x0000 (---------------) + I mulhouse 0x002c7846, // n0x14fb c0x0000 (---------------) + I muncie 0x002c9c06, // n0x14fc c0x0000 (---------------) + I museet 0x002d5acc, // n0x14fd c0x0000 (---------------) + I museumcenter 0x002ca1d0, // n0x14fe c0x0000 (---------------) + I museumvereniging 0x002769c5, // n0x14ff c0x0000 (---------------) + I music 0x002f8248, // n0x1500 c0x0000 (---------------) + I national 0x002f8250, // n0x1501 c0x0000 (---------------) + I nationalfirearms 0x003878d0, // n0x1502 c0x0000 (---------------) + I nationalheritage 0x0032678e, // n0x1503 c0x0000 (---------------) + I nativeamerican 0x002d574e, // n0x1504 c0x0000 (---------------) + I naturalhistory 0x002d5754, // n0x1505 c0x0000 (---------------) + I naturalhistorymuseum 0x0030464f, // n0x1506 c0x0000 (---------------) + I naturalsciences 0x00304a06, // n0x1507 c0x0000 (---------------) + I nature 0x00309891, // n0x1508 c0x0000 (---------------) + I naturhistorisches 0x00335b53, // n0x1509 c0x0000 (---------------) + I natuurwetenschappen 0x00335fc8, // n0x150a c0x0000 (---------------) + I naumburg 0x00303c05, // n0x150b c0x0000 (---------------) + I naval 0x002724c8, // n0x150c c0x0000 (---------------) + I nebraska 0x002bc5c5, // n0x150d c0x0000 (---------------) + I neues 0x00226b8c, // n0x150e c0x0000 (---------------) + I newhampshire 0x00299b89, // n0x150f c0x0000 (---------------) + I newjersey 0x0022a8c9, // n0x1510 c0x0000 (---------------) + I newmexico 0x0023f387, // n0x1511 c0x0000 (---------------) + I newport 0x00229689, // n0x1512 c0x0000 (---------------) + I newspaper 0x00338e87, // n0x1513 c0x0000 (---------------) + I newyork 0x00287906, // n0x1514 c0x0000 (---------------) + I niepce 0x00373547, // n0x1515 c0x0000 (---------------) + I norfolk 0x00235205, // n0x1516 c0x0000 (---------------) + I north 0x00351e43, // n0x1517 c0x0000 (---------------) + I nrw 0x0033a349, // n0x1518 c0x0000 (---------------) + I nuernberg 0x0020a609, // n0x1519 c0x0000 (---------------) + I nuremberg 0x0036aa83, // n0x151a c0x0000 (---------------) + I nyc 0x00397b84, // n0x151b c0x0000 (---------------) + I nyny 0x003138cd, // n0x151c c0x0000 (---------------) + I oceanographic 0x0020074f, // n0x151d c0x0000 (---------------) + I oceanographique 0x002f2fc5, // n0x151e c0x0000 (---------------) + I omaha 0x00310ac6, // n0x151f c0x0000 (---------------) + I online 0x00208f87, // n0x1520 c0x0000 (---------------) + I ontario 0x0033ba87, // n0x1521 c0x0000 (---------------) + I openair 0x002828c6, // n0x1522 c0x0000 (---------------) + I oregon 0x002828cb, // n0x1523 c0x0000 (---------------) + I oregontrail 0x0029cf85, // n0x1524 c0x0000 (---------------) + I otago 0x00393506, // n0x1525 c0x0000 (---------------) + I oxford 0x00203947, // n0x1526 c0x0000 (---------------) + I pacific 0x00268789, // n0x1527 c0x0000 (---------------) + I paderborn 0x00350d46, // n0x1528 c0x0000 (---------------) + I palace 0x0020fc45, // n0x1529 c0x0000 (---------------) + I paleo 0x003520cb, // n0x152a c0x0000 (---------------) + I palmsprings 0x00359f46, // n0x152b c0x0000 (---------------) + I panama 0x00266185, // n0x152c c0x0000 (---------------) + I paris 0x002b0188, // n0x152d c0x0000 (---------------) + I pasadena 0x00349688, // n0x152e c0x0000 (---------------) + I pharmacy 0x002cd50c, // n0x152f c0x0000 (---------------) + I philadelphia 0x002cd510, // n0x1530 c0x0000 (---------------) + I philadelphiaarea 0x002cdbc9, // n0x1531 c0x0000 (---------------) + I philately 0x002ce007, // n0x1532 c0x0000 (---------------) + I phoenix 0x002ce48b, // n0x1533 c0x0000 (---------------) + I photography 0x002cf9c6, // n0x1534 c0x0000 (---------------) + I pilots 0x002d064a, // n0x1535 c0x0000 (---------------) + I pittsburgh 0x002d110b, // n0x1536 c0x0000 (---------------) + I planetarium 0x002d1a0a, // n0x1537 c0x0000 (---------------) + I plantation 0x002d1c86, // n0x1538 c0x0000 (---------------) + I plants 0x002d2dc5, // n0x1539 c0x0000 (---------------) + I plaza 0x003382c6, // n0x153a c0x0000 (---------------) + I portal 0x0027dd48, // n0x153b c0x0000 (---------------) + I portland 0x0023f44a, // n0x153c c0x0000 (---------------) + I portlligat 0x0035b5dc, // n0x153d c0x0000 (---------------) + I posts-and-telecommunications 0x002d9dcc, // n0x153e c0x0000 (---------------) + I preservation 0x002da0c8, // n0x153f c0x0000 (---------------) + I presidio 0x002416c5, // n0x1540 c0x0000 (---------------) + I press 0x002dc707, // n0x1541 c0x0000 (---------------) + I project 0x00297d86, // n0x1542 c0x0000 (---------------) + I public 0x0037b745, // n0x1543 c0x0000 (---------------) + I pubol 0x00219d86, // n0x1544 c0x0000 (---------------) + I quebec 0x00282a88, // n0x1545 c0x0000 (---------------) + I railroad 0x002acf07, // n0x1546 c0x0000 (---------------) + I railway 0x00298048, // n0x1547 c0x0000 (---------------) + I research 0x0028338a, // n0x1548 c0x0000 (---------------) + I resistance 0x00314a4c, // n0x1549 c0x0000 (---------------) + I riodejaneiro 0x00314cc9, // n0x154a c0x0000 (---------------) + I rochester 0x00393807, // n0x154b c0x0000 (---------------) + I rockart 0x00227684, // n0x154c c0x0000 (---------------) + I roma 0x0024c586, // n0x154d c0x0000 (---------------) + I russia 0x0035a4ca, // n0x154e c0x0000 (---------------) + I saintlouis 0x00276585, // n0x154f c0x0000 (---------------) + I salem 0x0031c54c, // n0x1550 c0x0000 (---------------) + I salvadordali 0x00341788, // n0x1551 c0x0000 (---------------) + I salzburg 0x0022e748, // n0x1552 c0x0000 (---------------) + I sandiego 0x003921cc, // n0x1553 c0x0000 (---------------) + I sanfrancisco 0x0020bc0c, // n0x1554 c0x0000 (---------------) + I santabarbara 0x0020ee49, // n0x1555 c0x0000 (---------------) + I santacruz 0x0020f087, // n0x1556 c0x0000 (---------------) + I santafe 0x0034e8cc, // n0x1557 c0x0000 (---------------) + I saskatchewan 0x002b0ac4, // n0x1558 c0x0000 (---------------) + I satx 0x0032ca4a, // n0x1559 c0x0000 (---------------) + I savannahga 0x003a2f4c, // n0x155a c0x0000 (---------------) + I schlesisches 0x0026974b, // n0x155b c0x0000 (---------------) + I schoenbrunn 0x0037f40b, // n0x155c c0x0000 (---------------) + I schokoladen 0x00381f46, // n0x155d c0x0000 (---------------) + I school 0x0022df47, // n0x155e c0x0000 (---------------) + I schweiz 0x0022f207, // n0x155f c0x0000 (---------------) + I science 0x0022f20f, // n0x1560 c0x0000 (---------------) + I science-fiction 0x002e5c51, // n0x1561 c0x0000 (---------------) + I scienceandhistory 0x00308852, // n0x1562 c0x0000 (---------------) + I scienceandindustry 0x0022f94d, // n0x1563 c0x0000 (---------------) + I sciencecenter 0x0022f94e, // n0x1564 c0x0000 (---------------) + I sciencecenters 0x0022fc8e, // n0x1565 c0x0000 (---------------) + I sciencehistory 0x00304808, // n0x1566 c0x0000 (---------------) + I sciences 0x00304812, // n0x1567 c0x0000 (---------------) + I sciencesnaturelles 0x00392408, // n0x1568 c0x0000 (---------------) + I scotland 0x002f09c7, // n0x1569 c0x0000 (---------------) + I seaport 0x00248fca, // n0x156a c0x0000 (---------------) + I settlement 0x0021f0c8, // n0x156b c0x0000 (---------------) + I settlers 0x002518c5, // n0x156c c0x0000 (---------------) + I shell 0x002e3e0a, // n0x156d c0x0000 (---------------) + I sherbrooke 0x0021ca07, // n0x156e c0x0000 (---------------) + I sibenik 0x00352e04, // n0x156f c0x0000 (---------------) + I silk 0x00244243, // n0x1570 c0x0000 (---------------) + I ski 0x0028f985, // n0x1571 c0x0000 (---------------) + I skole 0x003542c7, // n0x1572 c0x0000 (---------------) + I society 0x002dae47, // n0x1573 c0x0000 (---------------) + I sologne 0x0028ce8e, // n0x1574 c0x0000 (---------------) + I soundandvision 0x002fcb4d, // n0x1575 c0x0000 (---------------) + I southcarolina 0x00322409, // n0x1576 c0x0000 (---------------) + I southwest 0x002046c5, // n0x1577 c0x0000 (---------------) + I space 0x003278c3, // n0x1578 c0x0000 (---------------) + I spy 0x003a3206, // n0x1579 c0x0000 (---------------) + I square 0x00360045, // n0x157a c0x0000 (---------------) + I stadt 0x00273448, // n0x157b c0x0000 (---------------) + I stalbans 0x0031b309, // n0x157c c0x0000 (---------------) + I starnberg 0x00209d85, // n0x157d c0x0000 (---------------) + I state 0x0032af8f, // n0x157e c0x0000 (---------------) + I stateofdelaware 0x002d2c07, // n0x157f c0x0000 (---------------) + I station 0x00362a45, // n0x1580 c0x0000 (---------------) + I steam 0x002cc60a, // n0x1581 c0x0000 (---------------) + I steiermark 0x002faf06, // n0x1582 c0x0000 (---------------) + I stjohn 0x00292389, // n0x1583 c0x0000 (---------------) + I stockholm 0x002dfd8c, // n0x1584 c0x0000 (---------------) + I stpetersburg 0x002e1109, // n0x1585 c0x0000 (---------------) + I stuttgart 0x00201146, // n0x1586 c0x0000 (---------------) + I suisse 0x00280d0c, // n0x1587 c0x0000 (---------------) + I surgeonshall 0x002e1986, // n0x1588 c0x0000 (---------------) + I surrey 0x002e4188, // n0x1589 c0x0000 (---------------) + I svizzera 0x002e4386, // n0x158a c0x0000 (---------------) + I sweden 0x00320146, // n0x158b c0x0000 (---------------) + I sydney 0x00256684, // n0x158c c0x0000 (---------------) + I tank 0x00256143, // n0x158d c0x0000 (---------------) + I tcm 0x002a59ca, // n0x158e c0x0000 (---------------) + I technology 0x00227991, // n0x158f c0x0000 (---------------) + I telekommunikation 0x002ae44a, // n0x1590 c0x0000 (---------------) + I television 0x00349245, // n0x1591 c0x0000 (---------------) + I texas 0x0031d607, // n0x1592 c0x0000 (---------------) + I textile 0x00250e47, // n0x1593 c0x0000 (---------------) + I theater 0x00218144, // n0x1594 c0x0000 (---------------) + I time 0x0021814b, // n0x1595 c0x0000 (---------------) + I timekeeping 0x00398848, // n0x1596 c0x0000 (---------------) + I topology 0x002ab806, // n0x1597 c0x0000 (---------------) + I torino 0x002f9b05, // n0x1598 c0x0000 (---------------) + I touch 0x002afb44, // n0x1599 c0x0000 (---------------) + I town 0x002945c9, // n0x159a c0x0000 (---------------) + I transport 0x00300584, // n0x159b c0x0000 (---------------) + I tree 0x002b22c7, // n0x159c c0x0000 (---------------) + I trolley 0x0031f7c5, // n0x159d c0x0000 (---------------) + I trust 0x0031f7c7, // n0x159e c0x0000 (---------------) + I trustee 0x00318b05, // n0x159f c0x0000 (---------------) + I uhren 0x0023fe83, // n0x15a0 c0x0000 (---------------) + I ulm 0x002f0888, // n0x15a1 c0x0000 (---------------) + I undersea 0x003179ca, // n0x15a2 c0x0000 (---------------) + I university 0x002056c3, // n0x15a3 c0x0000 (---------------) + I usa 0x002056ca, // n0x15a4 c0x0000 (---------------) + I usantiques 0x002873c6, // n0x15a5 c0x0000 (---------------) + I usarts 0x0032ad0f, // n0x15a6 c0x0000 (---------------) + I uscountryestate 0x0032db09, // n0x15a7 c0x0000 (---------------) + I usculture 0x00256c90, // n0x15a8 c0x0000 (---------------) + I usdecorativearts 0x00265648, // n0x15a9 c0x0000 (---------------) + I usgarden 0x002c3f09, // n0x15aa c0x0000 (---------------) + I ushistory 0x00295e47, // n0x15ab c0x0000 (---------------) + I ushuaia 0x002d7a4f, // n0x15ac c0x0000 (---------------) + I uslivinghistory 0x002e0c44, // n0x15ad c0x0000 (---------------) + I utah 0x0034ec84, // n0x15ae c0x0000 (---------------) + I uvic 0x002175c6, // n0x15af c0x0000 (---------------) + I valley 0x00230906, // n0x15b0 c0x0000 (---------------) + I vantaa 0x0030e40a, // n0x15b1 c0x0000 (---------------) + I versailles 0x0022d5c6, // n0x15b2 c0x0000 (---------------) + I viking 0x002ecb87, // n0x15b3 c0x0000 (---------------) + I village 0x002edf48, // n0x15b4 c0x0000 (---------------) + I virginia 0x002ee147, // n0x15b5 c0x0000 (---------------) + I virtual 0x002ee307, // n0x15b6 c0x0000 (---------------) + I virtuel 0x0034374a, // n0x15b7 c0x0000 (---------------) + I vlaanderen 0x002f06cb, // n0x15b8 c0x0000 (---------------) + I volkenkunde 0x002c2085, // n0x15b9 c0x0000 (---------------) + I wales 0x00308488, // n0x15ba c0x0000 (---------------) + I wallonie 0x0022ab83, // n0x15bb c0x0000 (---------------) + I war 0x00289fcc, // n0x15bc c0x0000 (---------------) + I washingtondc 0x0037088f, // n0x15bd c0x0000 (---------------) + I watch-and-clock 0x002a720d, // n0x15be c0x0000 (---------------) + I watchandclock 0x00235347, // n0x15bf c0x0000 (---------------) + I western 0x00322549, // n0x15c0 c0x0000 (---------------) + I westfalen 0x00351ec7, // n0x15c1 c0x0000 (---------------) + I whaling 0x00244e48, // n0x15c2 c0x0000 (---------------) + I wildlife 0x0022b94c, // n0x15c3 c0x0000 (---------------) + I williamsburg 0x0025b988, // n0x15c4 c0x0000 (---------------) + I windmill 0x00382648, // n0x15c5 c0x0000 (---------------) + I workshop 0x00305ece, // n0x15c6 c0x0000 (---------------) + I xn--9dbhblg6di 0x00316254, // n0x15c7 c0x0000 (---------------) + I xn--comunicaes-v6a2o 0x00316764, // n0x15c8 c0x0000 (---------------) + I xn--correios-e-telecomunicaes-ghc29a 0x0033204a, // n0x15c9 c0x0000 (---------------) + I xn--h1aegh 0x0035370b, // n0x15ca c0x0000 (---------------) + I xn--lns-qla 0x00338f44, // n0x15cb c0x0000 (---------------) + I york 0x00338f49, // n0x15cc c0x0000 (---------------) + I yorkshire 0x002e2248, // n0x15cd c0x0000 (---------------) + I yosemite 0x00243d85, // n0x15ce c0x0000 (---------------) + I youth 0x00339c8a, // n0x15cf c0x0000 (---------------) + I zoological 0x003a33c7, // n0x15d0 c0x0000 (---------------) + I zoology 0x002dbdc4, // n0x15d1 c0x0000 (---------------) + I aero 0x00325b83, // n0x15d2 c0x0000 (---------------) + I biz 0x0022d0c3, // n0x15d3 c0x0000 (---------------) + I com 0x00235044, // n0x15d4 c0x0000 (---------------) + I coop 0x002325c3, // n0x15d5 c0x0000 (---------------) + I edu 0x00264783, // n0x15d6 c0x0000 (---------------) + I gov 0x003a4f84, // n0x15d7 c0x0000 (---------------) + I info 0x00267a43, // n0x15d8 c0x0000 (---------------) + I int 0x00214d03, // n0x15d9 c0x0000 (---------------) + I mil 0x002ca1c6, // n0x15da c0x0000 (---------------) + I museum 0x0020ff84, // n0x15db c0x0000 (---------------) + I name 0x0021e283, // n0x15dc c0x0000 (---------------) + I net 0x00223a43, // n0x15dd c0x0000 (---------------) + I org 0x00220443, // n0x15de c0x0000 (---------------) + I pro 0x00203982, // n0x15df c0x0000 (---------------) + I ac 0x00325b83, // n0x15e0 c0x0000 (---------------) + I biz 0x00203dc2, // n0x15e1 c0x0000 (---------------) + I co 0x0022d0c3, // n0x15e2 c0x0000 (---------------) + I com 0x00235044, // n0x15e3 c0x0000 (---------------) + I coop 0x002325c3, // n0x15e4 c0x0000 (---------------) + I edu 0x00264783, // n0x15e5 c0x0000 (---------------) + I gov 0x00267a43, // n0x15e6 c0x0000 (---------------) + I int 0x002ca1c6, // n0x15e7 c0x0000 (---------------) + I museum 0x0021e283, // n0x15e8 c0x0000 (---------------) + I net 0x00223a43, // n0x15e9 c0x0000 (---------------) + I org 0x000f4e08, // n0x15ea c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x15eb c0x0000 (---------------) + I com 0x002325c3, // n0x15ec c0x0000 (---------------) + I edu 0x00210ec3, // n0x15ed c0x0000 (---------------) + I gob 0x0021e283, // n0x15ee c0x0000 (---------------) + I net 0x00223a43, // n0x15ef c0x0000 (---------------) + I org 0x000f4e08, // n0x15f0 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x15f1 c0x0000 (---------------) + I com 0x002325c3, // n0x15f2 c0x0000 (---------------) + I edu 0x00264783, // n0x15f3 c0x0000 (---------------) + I gov 0x00214d03, // n0x15f4 c0x0000 (---------------) + I mil 0x0020ff84, // n0x15f5 c0x0000 (---------------) + I name 0x0021e283, // n0x15f6 c0x0000 (---------------) + I net 0x00223a43, // n0x15f7 c0x0000 (---------------) + I org 0x006af1c8, // n0x15f8 c0x0001 (---------------) ! I teledata 0x00200302, // n0x15f9 c0x0000 (---------------) + I ca 0x0021e542, // n0x15fa c0x0000 (---------------) + I cc 0x00203dc2, // n0x15fb c0x0000 (---------------) + I co 0x0022d0c3, // n0x15fc c0x0000 (---------------) + I com 0x00205c82, // n0x15fd c0x0000 (---------------) + I dr 0x00202082, // n0x15fe c0x0000 (---------------) + I in 0x003a4f84, // n0x15ff c0x0000 (---------------) + I info 0x00207c84, // n0x1600 c0x0000 (---------------) + I mobi 0x00216582, // n0x1601 c0x0000 (---------------) + I mx 0x0020ff84, // n0x1602 c0x0000 (---------------) + I name 0x00200282, // n0x1603 c0x0000 (---------------) + I or 0x00223a43, // n0x1604 c0x0000 (---------------) + I org 0x00220443, // n0x1605 c0x0000 (---------------) + I pro 0x00381f46, // n0x1606 c0x0000 (---------------) + I school 0x0020da42, // n0x1607 c0x0000 (---------------) + I tv 0x00201102, // n0x1608 c0x0000 (---------------) + I us 0x002044c2, // n0x1609 c0x0000 (---------------) + I ws 0x37e21143, // n0x160a c0x00df (n0x160c-n0x160d) o I her 0x38212fc3, // n0x160b c0x00e0 (n0x160d-n0x160e) o I his 0x000516c6, // n0x160c c0x0000 (---------------) + forgot 0x000516c6, // n0x160d c0x0000 (---------------) + forgot 0x002c7fc4, // n0x160e c0x0000 (---------------) + I asso 0x0011010c, // n0x160f c0x0000 (---------------) + at-band-camp 0x0007984c, // n0x1610 c0x0000 (---------------) + azure-mobile 0x000bb10d, // n0x1611 c0x0000 (---------------) + azurewebsites 0x00025387, // n0x1612 c0x0000 (---------------) + blogdns 0x0001ec08, // n0x1613 c0x0000 (---------------) + broke-it 0x00191f8a, // n0x1614 c0x0000 (---------------) + buyshouses 0x38e36505, // n0x1615 c0x00e3 (n0x1643-n0x1644) o I cdn77 0x00036509, // n0x1616 c0x0000 (---------------) + cdn77-ssl 0x00101c88, // n0x1617 c0x0000 (---------------) + cloudapp 0x0019614a, // n0x1618 c0x0000 (---------------) + cloudfront 0x001480c8, // n0x1619 c0x0000 (---------------) + dnsalias 0x000749c7, // n0x161a c0x0000 (---------------) + dnsdojo 0x0000d8c7, // n0x161b c0x0000 (---------------) + does-it 0x00165b89, // n0x161c c0x0000 (---------------) + dontexist 0x001a2cc7, // n0x161d c0x0000 (---------------) + dsmynas 0x00189b08, // n0x161e c0x0000 (---------------) + dynalias 0x000ec389, // n0x161f c0x0000 (---------------) + dynathome 0x000a2acd, // n0x1620 c0x0000 (---------------) + endofinternet 0x001a2b48, // n0x1621 c0x0000 (---------------) + familyds 0x3923ba86, // n0x1622 c0x00e4 (n0x1644-n0x1646) o I fastly 0x0005b7c7, // n0x1623 c0x0000 (---------------) + from-az 0x0005d087, // n0x1624 c0x0000 (---------------) + from-co 0x00061e07, // n0x1625 c0x0000 (---------------) + from-la 0x00067c87, // n0x1626 c0x0000 (---------------) + from-ny 0x0000a482, // n0x1627 c0x0000 (---------------) + gb 0x00039a87, // n0x1628 c0x0000 (---------------) + gets-it 0x00045b0c, // n0x1629 c0x0000 (---------------) + ham-radio-op 0x00141e07, // n0x162a c0x0000 (---------------) + homeftp 0x0009ea06, // n0x162b c0x0000 (---------------) + homeip 0x0009f749, // n0x162c c0x0000 (---------------) + homelinux 0x000a0bc8, // n0x162d c0x0000 (---------------) + homeunix 0x00022f82, // n0x162e c0x0000 (---------------) + hu 0x00002082, // n0x162f c0x0000 (---------------) + in 0x001982cb, // n0x1630 c0x0000 (---------------) + in-the-band 0x00011709, // n0x1631 c0x0000 (---------------) + is-a-chef 0x00043289, // n0x1632 c0x0000 (---------------) + is-a-geek 0x000fdf48, // n0x1633 c0x0000 (---------------) + isa-geek 0x000a8442, // n0x1634 c0x0000 (---------------) + jp 0x0014d5c9, // n0x1635 c0x0000 (---------------) + kicks-ass 0x00028f4d, // n0x1636 c0x0000 (---------------) + office-on-the 0x000d67c7, // n0x1637 c0x0000 (---------------) + podzone 0x001388c8, // n0x1638 c0x0000 (---------------) + rackmaze 0x0003d74d, // n0x1639 c0x0000 (---------------) + scrapper-site 0x00001242, // n0x163a c0x0000 (---------------) + se 0x000636c6, // n0x163b c0x0000 (---------------) + selfip 0x0008a788, // n0x163c c0x0000 (---------------) + sells-it 0x000c7008, // n0x163d c0x0000 (---------------) + servebbs 0x0006ef08, // n0x163e c0x0000 (---------------) + serveftp 0x0004d048, // n0x163f c0x0000 (---------------) + thruhere 0x00000bc2, // n0x1640 c0x0000 (---------------) + uk 0x001374c6, // n0x1641 c0x0000 (---------------) + webhop 0x0000a182, // n0x1642 c0x0000 (---------------) + za 0x000002c1, // n0x1643 c0x0000 (---------------) + r 0x396dabc4, // n0x1644 c0x00e5 (n0x1646-n0x1648) o I prod 0x39a36683, // n0x1645 c0x00e6 (n0x1648-n0x164b) o I ssl 0x00000101, // n0x1646 c0x0000 (---------------) + a 0x0000ac06, // n0x1647 c0x0000 (---------------) + global 0x00000101, // n0x1648 c0x0000 (---------------) + a 0x00000001, // n0x1649 c0x0000 (---------------) + b 0x0000ac06, // n0x164a c0x0000 (---------------) + global 0x00244d04, // n0x164b c0x0000 (---------------) + I arts 0x0022d0c3, // n0x164c c0x0000 (---------------) + I com 0x00246bc4, // n0x164d c0x0000 (---------------) + I firm 0x003a4f84, // n0x164e c0x0000 (---------------) + I info 0x0021e283, // n0x164f c0x0000 (---------------) + I net 0x002210c5, // n0x1650 c0x0000 (---------------) + I other 0x00220503, // n0x1651 c0x0000 (---------------) + I per 0x00226e03, // n0x1652 c0x0000 (---------------) + I rec 0x003758c5, // n0x1653 c0x0000 (---------------) + I store 0x002292c3, // n0x1654 c0x0000 (---------------) + I web 0x3a62d0c3, // n0x1655 c0x00e9 (n0x165e-n0x165f) + I com 0x002325c3, // n0x1656 c0x0000 (---------------) + I edu 0x00264783, // n0x1657 c0x0000 (---------------) + I gov 0x00214d03, // n0x1658 c0x0000 (---------------) + I mil 0x00207c84, // n0x1659 c0x0000 (---------------) + I mobi 0x0020ff84, // n0x165a c0x0000 (---------------) + I name 0x0021e283, // n0x165b c0x0000 (---------------) + I net 0x00223a43, // n0x165c c0x0000 (---------------) + I org 0x00213403, // n0x165d c0x0000 (---------------) + I sch 0x000f4e08, // n0x165e c0x0000 (---------------) + blogspot 0x00203982, // n0x165f c0x0000 (---------------) + I ac 0x00325b83, // n0x1660 c0x0000 (---------------) + I biz 0x00203dc2, // n0x1661 c0x0000 (---------------) + I co 0x0022d0c3, // n0x1662 c0x0000 (---------------) + I com 0x002325c3, // n0x1663 c0x0000 (---------------) + I edu 0x00210ec3, // n0x1664 c0x0000 (---------------) + I gob 0x00202082, // n0x1665 c0x0000 (---------------) + I in 0x003a4f84, // n0x1666 c0x0000 (---------------) + I info 0x00267a43, // n0x1667 c0x0000 (---------------) + I int 0x00214d03, // n0x1668 c0x0000 (---------------) + I mil 0x0021e283, // n0x1669 c0x0000 (---------------) + I net 0x0020f543, // n0x166a c0x0000 (---------------) + I nom 0x00223a43, // n0x166b c0x0000 (---------------) + I org 0x002292c3, // n0x166c c0x0000 (---------------) + I web 0x000f4e08, // n0x166d c0x0000 (---------------) + blogspot 0x00361402, // n0x166e c0x0000 (---------------) + I bv 0x00003dc2, // n0x166f c0x0000 (---------------) + co 0x3b621f42, // n0x1670 c0x00ed (n0x1946-n0x1947) + I aa 0x002ffc48, // n0x1671 c0x0000 (---------------) + I aarborte 0x002223c6, // n0x1672 c0x0000 (---------------) + I aejrie 0x002b6606, // n0x1673 c0x0000 (---------------) + I afjord 0x00221d47, // n0x1674 c0x0000 (---------------) + I agdenes 0x3ba09982, // n0x1675 c0x00ee (n0x1947-n0x1948) + I ah 0x3bf1e048, // n0x1676 c0x00ef (n0x1948-n0x1949) o I akershus 0x003a244a, // n0x1677 c0x0000 (---------------) + I aknoluokta 0x0025b248, // n0x1678 c0x0000 (---------------) + I akrehamn 0x002001c2, // n0x1679 c0x0000 (---------------) + I al 0x003a4409, // n0x167a c0x0000 (---------------) + I alaheadju 0x002c20c7, // n0x167b c0x0000 (---------------) + I alesund 0x00217906, // n0x167c c0x0000 (---------------) + I algard 0x0032bec9, // n0x167d c0x0000 (---------------) + I alstahaug 0x00232c04, // n0x167e c0x0000 (---------------) + I alta 0x002b7086, // n0x167f c0x0000 (---------------) + I alvdal 0x002b6a04, // n0x1680 c0x0000 (---------------) + I amli 0x002715c4, // n0x1681 c0x0000 (---------------) + I amot 0x00252f89, // n0x1682 c0x0000 (---------------) + I andasuolo 0x00205dc6, // n0x1683 c0x0000 (---------------) + I andebu 0x00229bc5, // n0x1684 c0x0000 (---------------) + I andoy 0x0025f985, // n0x1685 c0x0000 (---------------) + I ardal 0x0022db47, // n0x1686 c0x0000 (---------------) + I aremark 0x002b2f87, // n0x1687 c0x0000 (---------------) + I arendal 0x00336ac4, // n0x1688 c0x0000 (---------------) + I arna 0x00221f86, // n0x1689 c0x0000 (---------------) + I aseral 0x002db685, // n0x168a c0x0000 (---------------) + I asker 0x0034e345, // n0x168b c0x0000 (---------------) + I askim 0x002ea2c5, // n0x168c c0x0000 (---------------) + I askoy 0x003814c7, // n0x168d c0x0000 (---------------) + I askvoll 0x0024ee45, // n0x168e c0x0000 (---------------) + I asnes 0x00300b09, // n0x168f c0x0000 (---------------) + I audnedaln 0x002d4f45, // n0x1690 c0x0000 (---------------) + I aukra 0x002f0dc4, // n0x1691 c0x0000 (---------------) + I aure 0x0031ed47, // n0x1692 c0x0000 (---------------) + I aurland 0x002fea4e, // n0x1693 c0x0000 (---------------) + I aurskog-holand 0x00304289, // n0x1694 c0x0000 (---------------) + I austevoll 0x00318789, // n0x1695 c0x0000 (---------------) + I austrheim 0x00335386, // n0x1696 c0x0000 (---------------) + I averoy 0x002e6488, // n0x1697 c0x0000 (---------------) + I badaddja 0x002a7e8b, // n0x1698 c0x0000 (---------------) + I bahcavuotna 0x002cb80c, // n0x1699 c0x0000 (---------------) + I bahccavuotna 0x00262086, // n0x169a c0x0000 (---------------) + I baidar 0x0036c647, // n0x169b c0x0000 (---------------) + I bajddar 0x00225e05, // n0x169c c0x0000 (---------------) + I balat 0x002379ca, // n0x169d c0x0000 (---------------) + I balestrand 0x00302a09, // n0x169e c0x0000 (---------------) + I ballangen 0x002562c9, // n0x169f c0x0000 (---------------) + I balsfjord 0x003953c6, // n0x16a0 c0x0000 (---------------) + I bamble 0x002e35c5, // n0x16a1 c0x0000 (---------------) + I bardu 0x00278d45, // n0x16a2 c0x0000 (---------------) + I barum 0x00350ac9, // n0x16a3 c0x0000 (---------------) + I batsfjord 0x002ea44b, // n0x16a4 c0x0000 (---------------) + I bearalvahki 0x00274686, // n0x16a5 c0x0000 (---------------) + I beardu 0x00324586, // n0x16a6 c0x0000 (---------------) + I beiarn 0x0020a3c4, // n0x16a7 c0x0000 (---------------) + I berg 0x00284d86, // n0x16a8 c0x0000 (---------------) + I bergen 0x00238508, // n0x16a9 c0x0000 (---------------) + I berlevag 0x00200006, // n0x16aa c0x0000 (---------------) + I bievat 0x003871c6, // n0x16ab c0x0000 (---------------) + I bindal 0x002065c8, // n0x16ac c0x0000 (---------------) + I birkenes 0x00207647, // n0x16ad c0x0000 (---------------) + I bjarkoy 0x00207a49, // n0x16ae c0x0000 (---------------) + I bjerkreim 0x00208205, // n0x16af c0x0000 (---------------) + I bjugn 0x000f4e08, // n0x16b0 c0x0000 (---------------) + blogspot 0x0020d844, // n0x16b1 c0x0000 (---------------) + I bodo 0x002ef284, // n0x16b2 c0x0000 (---------------) + I bokn 0x0020ec85, // n0x16b3 c0x0000 (---------------) + I bomlo 0x00385409, // n0x16b4 c0x0000 (---------------) + I bremanger 0x00220887, // n0x16b5 c0x0000 (---------------) + I bronnoy 0x0022088b, // n0x16b6 c0x0000 (---------------) + I bronnoysund 0x0022164a, // n0x16b7 c0x0000 (---------------) + I brumunddal 0x00225b05, // n0x16b8 c0x0000 (---------------) + I bryne 0x3c205682, // n0x16b9 c0x00f0 (n0x1949-n0x194a) + I bu 0x00205ec7, // n0x16ba c0x0000 (---------------) + I budejju 0x3c626948, // n0x16bb c0x00f1 (n0x194a-n0x194b) o I buskerud 0x002cb3c7, // n0x16bc c0x0000 (---------------) + I bygland 0x002ae045, // n0x16bd c0x0000 (---------------) + I bykle 0x00236d8a, // n0x16be c0x0000 (---------------) + I cahcesuolo 0x00003dc2, // n0x16bf c0x0000 (---------------) + co 0x0025c9cb, // n0x16c0 c0x0000 (---------------) + I davvenjarga 0x0020c8ca, // n0x16c1 c0x0000 (---------------) + I davvesiida 0x00393646, // n0x16c2 c0x0000 (---------------) + I deatnu 0x0026ce83, // n0x16c3 c0x0000 (---------------) + I dep 0x00399d4d, // n0x16c4 c0x0000 (---------------) + I dielddanuorri 0x002fe4cc, // n0x16c5 c0x0000 (---------------) + I divtasvuodna 0x0030344d, // n0x16c6 c0x0000 (---------------) + I divttasvuotna 0x00359745, // n0x16c7 c0x0000 (---------------) + I donna 0x00261b45, // n0x16c8 c0x0000 (---------------) + I dovre 0x0033a1c7, // n0x16c9 c0x0000 (---------------) + I drammen 0x003925c9, // n0x16ca c0x0000 (---------------) + I drangedal 0x003a2346, // n0x16cb c0x0000 (---------------) + I drobak 0x0022d445, // n0x16cc c0x0000 (---------------) + I dyroy 0x0021e688, // n0x16cd c0x0000 (---------------) + I egersund 0x002727c3, // n0x16ce c0x0000 (---------------) + I eid 0x0030b3c8, // n0x16cf c0x0000 (---------------) + I eidfjord 0x00284c88, // n0x16d0 c0x0000 (---------------) + I eidsberg 0x002b7f87, // n0x16d1 c0x0000 (---------------) + I eidskog 0x002727c8, // n0x16d2 c0x0000 (---------------) + I eidsvoll 0x003a1f49, // n0x16d3 c0x0000 (---------------) + I eigersund 0x002343c7, // n0x16d4 c0x0000 (---------------) + I elverum 0x002ff647, // n0x16d5 c0x0000 (---------------) + I enebakk 0x0027e308, // n0x16d6 c0x0000 (---------------) + I engerdal 0x002f2a84, // n0x16d7 c0x0000 (---------------) + I etne 0x002f2a87, // n0x16d8 c0x0000 (---------------) + I etnedal 0x00241e88, // n0x16d9 c0x0000 (---------------) + I evenassi 0x00201d46, // n0x16da c0x0000 (---------------) + I evenes 0x0037c54f, // n0x16db c0x0000 (---------------) + I evje-og-hornnes 0x00211907, // n0x16dc c0x0000 (---------------) + I farsund 0x00240586, // n0x16dd c0x0000 (---------------) + I fauske 0x00246e85, // n0x16de c0x0000 (---------------) + I fedje 0x00340703, // n0x16df c0x0000 (---------------) + I fet 0x00340707, // n0x16e0 c0x0000 (---------------) + I fetsund 0x0022b203, // n0x16e1 c0x0000 (---------------) + I fhs 0x00245346, // n0x16e2 c0x0000 (---------------) + I finnoy 0x00247c86, // n0x16e3 c0x0000 (---------------) + I fitjar 0x00249386, // n0x16e4 c0x0000 (---------------) + I fjaler 0x00288985, // n0x16e5 c0x0000 (---------------) + I fjell 0x0025e843, // n0x16e6 c0x0000 (---------------) + I fla 0x00377cc8, // n0x16e7 c0x0000 (---------------) + I flakstad 0x003941c9, // n0x16e8 c0x0000 (---------------) + I flatanger 0x0036090b, // n0x16e9 c0x0000 (---------------) + I flekkefjord 0x00370f48, // n0x16ea c0x0000 (---------------) + I flesberg 0x0024bc05, // n0x16eb c0x0000 (---------------) + I flora 0x0024c705, // n0x16ec c0x0000 (---------------) + I floro 0x3ca2c142, // n0x16ed c0x00f2 (n0x194b-n0x194c) + I fm 0x00373609, // n0x16ee c0x0000 (---------------) + I folkebibl 0x0024f747, // n0x16ef c0x0000 (---------------) + I folldal 0x00393585, // n0x16f0 c0x0000 (---------------) + I forde 0x00252e87, // n0x16f1 c0x0000 (---------------) + I forsand 0x002552c6, // n0x16f2 c0x0000 (---------------) + I fosnes 0x00358705, // n0x16f3 c0x0000 (---------------) + I frana 0x0035fe8b, // n0x16f4 c0x0000 (---------------) + I fredrikstad 0x00255dc4, // n0x16f5 c0x0000 (---------------) + I frei 0x0025ae05, // n0x16f6 c0x0000 (---------------) + I frogn 0x0025af47, // n0x16f7 c0x0000 (---------------) + I froland 0x0026f886, // n0x16f8 c0x0000 (---------------) + I frosta 0x0026fcc5, // n0x16f9 c0x0000 (---------------) + I froya 0x0027bc87, // n0x16fa c0x0000 (---------------) + I fuoisku 0x0027cd07, // n0x16fb c0x0000 (---------------) + I fuossko 0x00287384, // n0x16fc c0x0000 (---------------) + I fusa 0x00283d8a, // n0x16fd c0x0000 (---------------) + I fylkesbibl 0x00284248, // n0x16fe c0x0000 (---------------) + I fyresdal 0x0038c509, // n0x16ff c0x0000 (---------------) + I gaivuotna 0x0021cdc5, // n0x1700 c0x0000 (---------------) + I galsa 0x0025cc06, // n0x1701 c0x0000 (---------------) + I gamvik 0x002386ca, // n0x1702 c0x0000 (---------------) + I gangaviika 0x0025f886, // n0x1703 c0x0000 (---------------) + I gaular 0x002af807, // n0x1704 c0x0000 (---------------) + I gausdal 0x0038c1cd, // n0x1705 c0x0000 (---------------) + I giehtavuoatna 0x00264f09, // n0x1706 c0x0000 (---------------) + I gildeskal 0x0023a605, // n0x1707 c0x0000 (---------------) + I giske 0x0026b947, // n0x1708 c0x0000 (---------------) + I gjemnes 0x00319048, // n0x1709 c0x0000 (---------------) + I gjerdrum 0x00336188, // n0x170a c0x0000 (---------------) + I gjerstad 0x00342747, // n0x170b c0x0000 (---------------) + I gjesdal 0x00318446, // n0x170c c0x0000 (---------------) + I gjovik 0x002108c7, // n0x170d c0x0000 (---------------) + I gloppen 0x00246dc3, // n0x170e c0x0000 (---------------) + I gol 0x00328ec4, // n0x170f c0x0000 (---------------) + I gran 0x003556c5, // n0x1710 c0x0000 (---------------) + I grane 0x0037cd47, // n0x1711 c0x0000 (---------------) + I granvin 0x00380ec9, // n0x1712 c0x0000 (---------------) + I gratangen 0x00219f48, // n0x1713 c0x0000 (---------------) + I grimstad 0x002af705, // n0x1714 c0x0000 (---------------) + I grong 0x00372604, // n0x1715 c0x0000 (---------------) + I grue 0x0022d705, // n0x1716 c0x0000 (---------------) + I gulen 0x0023fb8d, // n0x1717 c0x0000 (---------------) + I guovdageaidnu 0x00202f42, // n0x1718 c0x0000 (---------------) + I ha 0x0035ab46, // n0x1719 c0x0000 (---------------) + I habmer 0x00263606, // n0x171a c0x0000 (---------------) + I hadsel 0x0029fbca, // n0x171b c0x0000 (---------------) + I hagebostad 0x00346d46, // n0x171c c0x0000 (---------------) + I halden 0x0035a405, // n0x171d c0x0000 (---------------) + I halsa 0x002ff385, // n0x171e c0x0000 (---------------) + I hamar 0x002ff387, // n0x171f c0x0000 (---------------) + I hamaroy 0x00369a0c, // n0x1720 c0x0000 (---------------) + I hammarfeasta 0x002776ca, // n0x1721 c0x0000 (---------------) + I hammerfest 0x00284646, // n0x1722 c0x0000 (---------------) + I hapmir 0x002ba7c5, // n0x1723 c0x0000 (---------------) + I haram 0x00284bc6, // n0x1724 c0x0000 (---------------) + I hareid 0x00284f07, // n0x1725 c0x0000 (---------------) + I harstad 0x00286246, // n0x1726 c0x0000 (---------------) + I hasvik 0x0028888c, // n0x1727 c0x0000 (---------------) + I hattfjelldal 0x0032c009, // n0x1728 c0x0000 (---------------) + I haugesund 0x3ce30347, // n0x1729 c0x00f3 (n0x194c-n0x194f) o I hedmark 0x0028b805, // n0x172a c0x0000 (---------------) + I hemne 0x0028b806, // n0x172b c0x0000 (---------------) + I hemnes 0x0028be48, // n0x172c c0x0000 (---------------) + I hemsedal 0x002aa345, // n0x172d c0x0000 (---------------) + I herad 0x0029ddc5, // n0x172e c0x0000 (---------------) + I hitra 0x0029e008, // n0x172f c0x0000 (---------------) + I hjartdal 0x0029e20a, // n0x1730 c0x0000 (---------------) + I hjelmeland 0x3d24e142, // n0x1731 c0x00f4 (n0x194f-n0x1950) + I hl 0x3d60b742, // n0x1732 c0x00f5 (n0x1950-n0x1951) + I hm 0x00371e85, // n0x1733 c0x0000 (---------------) + I hobol 0x002b0603, // n0x1734 c0x0000 (---------------) + I hof 0x003822c8, // n0x1735 c0x0000 (---------------) + I hokksund 0x002924c3, // n0x1736 c0x0000 (---------------) + I hol 0x0029e484, // n0x1737 c0x0000 (---------------) + I hole 0x002924cb, // n0x1738 c0x0000 (---------------) + I holmestrand 0x002a8248, // n0x1739 c0x0000 (---------------) + I holtalen 0x002a13c8, // n0x173a c0x0000 (---------------) + I honefoss 0x3db1db89, // n0x173b c0x00f6 (n0x1951-n0x1952) o I hordaland 0x002a2549, // n0x173c c0x0000 (---------------) + I hornindal 0x002a29c6, // n0x173d c0x0000 (---------------) + I horten 0x002a3b48, // n0x173e c0x0000 (---------------) + I hoyanger 0x002a3d49, // n0x173f c0x0000 (---------------) + I hoylandet 0x002a5186, // n0x1740 c0x0000 (---------------) + I hurdal 0x002a5305, // n0x1741 c0x0000 (---------------) + I hurum 0x0035f206, // n0x1742 c0x0000 (---------------) + I hvaler 0x002a5c49, // n0x1743 c0x0000 (---------------) + I hyllestad 0x00238a47, // n0x1744 c0x0000 (---------------) + I ibestad 0x00265cc6, // n0x1745 c0x0000 (---------------) + I idrett 0x00376387, // n0x1746 c0x0000 (---------------) + I inderoy 0x003a21c7, // n0x1747 c0x0000 (---------------) + I iveland 0x00275404, // n0x1748 c0x0000 (---------------) + I ivgu 0x3de1ba49, // n0x1749 c0x00f7 (n0x1952-n0x1953) + I jan-mayen 0x002c0788, // n0x174a c0x0000 (---------------) + I jessheim 0x00351648, // n0x174b c0x0000 (---------------) + I jevnaker 0x0022c7c7, // n0x174c c0x0000 (---------------) + I jolster 0x002bbb86, // n0x174d c0x0000 (---------------) + I jondal 0x002f31c9, // n0x174e c0x0000 (---------------) + I jorpeland 0x002b7547, // n0x174f c0x0000 (---------------) + I kafjord 0x0025494a, // n0x1750 c0x0000 (---------------) + I karasjohka 0x002e7108, // n0x1751 c0x0000 (---------------) + I karasjok 0x00239047, // n0x1752 c0x0000 (---------------) + I karlsoy 0x00239506, // n0x1753 c0x0000 (---------------) + I karmoy 0x0021dc4a, // n0x1754 c0x0000 (---------------) + I kautokeino 0x00276fc8, // n0x1755 c0x0000 (---------------) + I kirkenes 0x00263085, // n0x1756 c0x0000 (---------------) + I klabu 0x0022a045, // n0x1757 c0x0000 (---------------) + I klepp 0x002ac7c7, // n0x1758 c0x0000 (---------------) + I kommune 0x002bf7c9, // n0x1759 c0x0000 (---------------) + I kongsberg 0x002c4acb, // n0x175a c0x0000 (---------------) + I kongsvinger 0x002cfd88, // n0x175b c0x0000 (---------------) + I kopervik 0x002d4fc9, // n0x175c c0x0000 (---------------) + I kraanghke 0x00249607, // n0x175d c0x0000 (---------------) + I kragero 0x002a95cc, // n0x175e c0x0000 (---------------) + I kristiansand 0x002a9f0c, // n0x175f c0x0000 (---------------) + I kristiansund 0x002aa20a, // n0x1760 c0x0000 (---------------) + I krodsherad 0x002aa48c, // n0x1761 c0x0000 (---------------) + I krokstadelva 0x002b6588, // n0x1762 c0x0000 (---------------) + I kvafjord 0x002b6788, // n0x1763 c0x0000 (---------------) + I kvalsund 0x002b6984, // n0x1764 c0x0000 (---------------) + I kvam 0x002b7709, // n0x1765 c0x0000 (---------------) + I kvanangen 0x002b7949, // n0x1766 c0x0000 (---------------) + I kvinesdal 0x002b7b8a, // n0x1767 c0x0000 (---------------) + I kvinnherad 0x002b7e09, // n0x1768 c0x0000 (---------------) + I kviteseid 0x002b8147, // n0x1769 c0x0000 (---------------) + I kvitsoy 0x003a064c, // n0x176a c0x0000 (---------------) + I laakesvuemie 0x0032b506, // n0x176b c0x0000 (---------------) + I lahppi 0x0024a448, // n0x176c c0x0000 (---------------) + I langevag 0x0025f946, // n0x176d c0x0000 (---------------) + I lardal 0x00376d86, // n0x176e c0x0000 (---------------) + I larvik 0x0023a507, // n0x176f c0x0000 (---------------) + I lavagis 0x00304488, // n0x1770 c0x0000 (---------------) + I lavangen 0x00319e8b, // n0x1771 c0x0000 (---------------) + I leangaviika 0x002cb287, // n0x1772 c0x0000 (---------------) + I lebesby 0x00252c49, // n0x1773 c0x0000 (---------------) + I leikanger 0x00279ac9, // n0x1774 c0x0000 (---------------) + I leirfjord 0x00358bc7, // n0x1775 c0x0000 (---------------) + I leirvik 0x002b6c44, // n0x1776 c0x0000 (---------------) + I leka 0x0031d747, // n0x1777 c0x0000 (---------------) + I leksvik 0x0024e786, // n0x1778 c0x0000 (---------------) + I lenvik 0x002135c6, // n0x1779 c0x0000 (---------------) + I lerdal 0x002c1245, // n0x177a c0x0000 (---------------) + I lesja 0x002ca988, // n0x177b c0x0000 (---------------) + I levanger 0x002bc4c4, // n0x177c c0x0000 (---------------) + I lier 0x002bc4c6, // n0x177d c0x0000 (---------------) + I lierne 0x0027758b, // n0x177e c0x0000 (---------------) + I lillehammer 0x003428c9, // n0x177f c0x0000 (---------------) + I lillesand 0x00314506, // n0x1780 c0x0000 (---------------) + I lindas 0x00387309, // n0x1781 c0x0000 (---------------) + I lindesnes 0x00381646, // n0x1782 c0x0000 (---------------) + I loabat 0x00253148, // n0x1783 c0x0000 (---------------) + I lodingen 0x00212ac3, // n0x1784 c0x0000 (---------------) + I lom 0x00203885, // n0x1785 c0x0000 (---------------) + I loppa 0x00213709, // n0x1786 c0x0000 (---------------) + I lorenskog 0x00215d05, // n0x1787 c0x0000 (---------------) + I loten 0x002dbac4, // n0x1788 c0x0000 (---------------) + I lund 0x0026eb06, // n0x1789 c0x0000 (---------------) + I lunner 0x00382905, // n0x178a c0x0000 (---------------) + I luroy 0x002d6586, // n0x178b c0x0000 (---------------) + I luster 0x002f3487, // n0x178c c0x0000 (---------------) + I lyngdal 0x00390706, // n0x178d c0x0000 (---------------) + I lyngen 0x0029108b, // n0x178e c0x0000 (---------------) + I malatvuopmi 0x0027fec7, // n0x178f c0x0000 (---------------) + I malselv 0x0020dd06, // n0x1790 c0x0000 (---------------) + I malvik 0x0034c686, // n0x1791 c0x0000 (---------------) + I mandal 0x0022dc06, // n0x1792 c0x0000 (---------------) + I marker 0x00336a89, // n0x1793 c0x0000 (---------------) + I marnardal 0x0021518a, // n0x1794 c0x0000 (---------------) + I masfjorden 0x003242c5, // n0x1795 c0x0000 (---------------) + I masoy 0x002232cd, // n0x1796 c0x0000 (---------------) + I matta-varjjat 0x0029e306, // n0x1797 c0x0000 (---------------) + I meland 0x00212986, // n0x1798 c0x0000 (---------------) + I meldal 0x00281106, // n0x1799 c0x0000 (---------------) + I melhus 0x00292185, // n0x179a c0x0000 (---------------) + I meloy 0x0031df87, // n0x179b c0x0000 (---------------) + I meraker 0x00296a47, // n0x179c c0x0000 (---------------) + I midsund 0x0034dece, // n0x179d c0x0000 (---------------) + I midtre-gauldal 0x00214d03, // n0x179e c0x0000 (---------------) + I mil 0x002bbb49, // n0x179f c0x0000 (---------------) + I mjondalen 0x0039ad89, // n0x17a0 c0x0000 (---------------) + I mo-i-rana 0x00237dc7, // n0x17a1 c0x0000 (---------------) + I moareke 0x00263cc7, // n0x17a2 c0x0000 (---------------) + I modalen 0x002a0545, // n0x17a3 c0x0000 (---------------) + I modum 0x00325a45, // n0x17a4 c0x0000 (---------------) + I molde 0x3e26a14f, // n0x17a5 c0x00f8 (n0x1953-n0x1955) o I more-og-romsdal 0x002c4147, // n0x17a6 c0x0000 (---------------) + I mosjoen 0x002c4308, // n0x17a7 c0x0000 (---------------) + I moskenes 0x002c4744, // n0x17a8 c0x0000 (---------------) + I moss 0x002c4986, // n0x17a9 c0x0000 (---------------) + I mosvik 0x3e6436c2, // n0x17aa c0x00f9 (n0x1955-n0x1956) + I mr 0x002c7ac6, // n0x17ab c0x0000 (---------------) + I muosat 0x002ca1c6, // n0x17ac c0x0000 (---------------) + I museum 0x0031a1ce, // n0x17ad c0x0000 (---------------) + I naamesjevuemie 0x0030b20a, // n0x17ae c0x0000 (---------------) + I namdalseid 0x002b0306, // n0x17af c0x0000 (---------------) + I namsos 0x0021f40a, // n0x17b0 c0x0000 (---------------) + I namsskogan 0x002be4c9, // n0x17b1 c0x0000 (---------------) + I nannestad 0x0030f245, // n0x17b2 c0x0000 (---------------) + I naroy 0x00383a88, // n0x17b3 c0x0000 (---------------) + I narviika 0x0039e4c6, // n0x17b4 c0x0000 (---------------) + I narvik 0x002d46c8, // n0x17b5 c0x0000 (---------------) + I naustdal 0x00308f08, // n0x17b6 c0x0000 (---------------) + I navuotna 0x00336f4b, // n0x17b7 c0x0000 (---------------) + I nedre-eiker 0x00221e45, // n0x17b8 c0x0000 (---------------) + I nesna 0x0024eec8, // n0x17b9 c0x0000 (---------------) + I nesodden 0x0020670c, // n0x17ba c0x0000 (---------------) + I nesoddtangen 0x002adf07, // n0x17bb c0x0000 (---------------) + I nesseby 0x00248f06, // n0x17bc c0x0000 (---------------) + I nesset 0x002afc08, // n0x17bd c0x0000 (---------------) + I nissedal 0x0027e608, // n0x17be c0x0000 (---------------) + I nittedal 0x3ea03842, // n0x17bf c0x00fa (n0x1956-n0x1957) + I nl 0x002b6e4b, // n0x17c0 c0x0000 (---------------) + I nord-aurdal 0x00389f49, // n0x17c1 c0x0000 (---------------) + I nord-fron 0x003484c9, // n0x17c2 c0x0000 (---------------) + I nord-odal 0x0023a387, // n0x17c3 c0x0000 (---------------) + I norddal 0x0026b748, // n0x17c4 c0x0000 (---------------) + I nordkapp 0x3ef1cc08, // n0x17c5 c0x00fb (n0x1957-n0x195b) o I nordland 0x00225f8b, // n0x17c6 c0x0000 (---------------) + I nordre-land 0x002fddc9, // n0x17c7 c0x0000 (---------------) + I nordreisa 0x0020e30d, // n0x17c8 c0x0000 (---------------) + I nore-og-uvdal 0x003396c8, // n0x17c9 c0x0000 (---------------) + I notodden 0x00305cc8, // n0x17ca c0x0000 (---------------) + I notteroy 0x3f204982, // n0x17cb c0x00fc (n0x195b-n0x195c) + I nt 0x00204e84, // n0x17cc c0x0000 (---------------) + I odda 0x3f603e02, // n0x17cd c0x00fd (n0x195c-n0x195d) + I of 0x002e7286, // n0x17ce c0x0000 (---------------) + I oksnes 0x3fa00fc2, // n0x17cf c0x00fe (n0x195d-n0x195e) + I ol 0x0022a2ca, // n0x17d0 c0x0000 (---------------) + I omasvuotna 0x003827c6, // n0x17d1 c0x0000 (---------------) + I oppdal 0x00224b48, // n0x17d2 c0x0000 (---------------) + I oppegard 0x0024fb08, // n0x17d3 c0x0000 (---------------) + I orkanger 0x002e6786, // n0x17d4 c0x0000 (---------------) + I orkdal 0x0033ce86, // n0x17d5 c0x0000 (---------------) + I orland 0x002de306, // n0x17d6 c0x0000 (---------------) + I orskog 0x002733c5, // n0x17d7 c0x0000 (---------------) + I orsta 0x0023b084, // n0x17d8 c0x0000 (---------------) + I osen 0x3febf244, // n0x17d9 c0x00ff (n0x195e-n0x195f) + I oslo 0x003296c6, // n0x17da c0x0000 (---------------) + I osoyro 0x0023ae87, // n0x17db c0x0000 (---------------) + I osteroy 0x4037bb47, // n0x17dc c0x0100 (n0x195f-n0x1960) o I ostfold 0x00349dcb, // n0x17dd c0x0000 (---------------) + I ostre-toten 0x002fee09, // n0x17de c0x0000 (---------------) + I overhalla 0x00261b8a, // n0x17df c0x0000 (---------------) + I ovre-eiker 0x003108c4, // n0x17e0 c0x0000 (---------------) + I oyer 0x002ff4c8, // n0x17e1 c0x0000 (---------------) + I oygarden 0x00265a8d, // n0x17e2 c0x0000 (---------------) + I oystre-slidre 0x002d8d49, // n0x17e3 c0x0000 (---------------) + I porsanger 0x002d8f88, // n0x17e4 c0x0000 (---------------) + I porsangu 0x002d9209, // n0x17e5 c0x0000 (---------------) + I porsgrunn 0x002da7c4, // n0x17e6 c0x0000 (---------------) + I priv 0x0021ac84, // n0x17e7 c0x0000 (---------------) + I rade 0x00278245, // n0x17e8 c0x0000 (---------------) + I radoy 0x0027008b, // n0x17e9 c0x0000 (---------------) + I rahkkeravju 0x002a81c6, // n0x17ea c0x0000 (---------------) + I raholt 0x00329505, // n0x17eb c0x0000 (---------------) + I raisa 0x003738c9, // n0x17ec c0x0000 (---------------) + I rakkestad 0x00222048, // n0x17ed c0x0000 (---------------) + I ralingen 0x00299044, // n0x17ee c0x0000 (---------------) + I rana 0x00237b49, // n0x17ef c0x0000 (---------------) + I randaberg 0x0024ddc5, // n0x17f0 c0x0000 (---------------) + I rauma 0x002b2fc8, // n0x17f1 c0x0000 (---------------) + I rendalen 0x0032ffc7, // n0x17f2 c0x0000 (---------------) + I rennebu 0x00318b88, // n0x17f3 c0x0000 (---------------) + I rennesoy 0x00278806, // n0x17f4 c0x0000 (---------------) + I rindal 0x0034dac7, // n0x17f5 c0x0000 (---------------) + I ringebu 0x0028b209, // n0x17f6 c0x0000 (---------------) + I ringerike 0x00352249, // n0x17f7 c0x0000 (---------------) + I ringsaker 0x00266205, // n0x17f8 c0x0000 (---------------) + I risor 0x0039a3c5, // n0x17f9 c0x0000 (---------------) + I rissa 0x40606182, // n0x17fa c0x0101 (n0x1960-n0x1961) + I rl 0x002f0b84, // n0x17fb c0x0000 (---------------) + I roan 0x002964c5, // n0x17fc c0x0000 (---------------) + I rodoy 0x0032fc86, // n0x17fd c0x0000 (---------------) + I rollag 0x00311a45, // n0x17fe c0x0000 (---------------) + I romsa 0x0024c7c7, // n0x17ff c0x0000 (---------------) + I romskog 0x0028f885, // n0x1800 c0x0000 (---------------) + I roros 0x0026f8c4, // n0x1801 c0x0000 (---------------) + I rost 0x00335446, // n0x1802 c0x0000 (---------------) + I royken 0x0022d4c7, // n0x1803 c0x0000 (---------------) + I royrvik 0x00243706, // n0x1804 c0x0000 (---------------) + I ruovat 0x00238d85, // n0x1805 c0x0000 (---------------) + I rygge 0x00303a48, // n0x1806 c0x0000 (---------------) + I salangen 0x002225c5, // n0x1807 c0x0000 (---------------) + I salat 0x00314387, // n0x1808 c0x0000 (---------------) + I saltdal 0x0037c8c9, // n0x1809 c0x0000 (---------------) + I samnanger 0x00342a0a, // n0x180a c0x0000 (---------------) + I sandefjord 0x00340bc7, // n0x180b c0x0000 (---------------) + I sandnes 0x00340bcc, // n0x180c c0x0000 (---------------) + I sandnessjoen 0x00229b86, // n0x180d c0x0000 (---------------) + I sandoy 0x002238c9, // n0x180e c0x0000 (---------------) + I sarpsborg 0x002d32c5, // n0x180f c0x0000 (---------------) + I sauda 0x0039fa48, // n0x1810 c0x0000 (---------------) + I sauherad 0x0020d603, // n0x1811 c0x0000 (---------------) + I sel 0x0020d605, // n0x1812 c0x0000 (---------------) + I selbu 0x0031fe85, // n0x1813 c0x0000 (---------------) + I selje 0x0022e9c7, // n0x1814 c0x0000 (---------------) + I seljord 0x40a11442, // n0x1815 c0x0102 (n0x1961-n0x1962) + I sf 0x0022e2c7, // n0x1816 c0x0000 (---------------) + I siellak 0x002f8606, // n0x1817 c0x0000 (---------------) + I sigdal 0x0021b986, // n0x1818 c0x0000 (---------------) + I siljan 0x002c4806, // n0x1819 c0x0000 (---------------) + I sirdal 0x0027e546, // n0x181a c0x0000 (---------------) + I skanit 0x00303288, // n0x181b c0x0000 (---------------) + I skanland 0x00272605, // n0x181c c0x0000 (---------------) + I skaun 0x00240647, // n0x181d c0x0000 (---------------) + I skedsmo 0x0024064d, // n0x181e c0x0000 (---------------) + I skedsmokorset 0x00244243, // n0x181f c0x0000 (---------------) + I ski 0x00302245, // n0x1820 c0x0000 (---------------) + I skien 0x002cc3c7, // n0x1821 c0x0000 (---------------) + I skierva 0x0026adc8, // n0x1822 c0x0000 (---------------) + I skiptvet 0x002cbf85, // n0x1823 c0x0000 (---------------) + I skjak 0x00225848, // n0x1824 c0x0000 (---------------) + I skjervoy 0x0036f3c6, // n0x1825 c0x0000 (---------------) + I skodje 0x002366c7, // n0x1826 c0x0000 (---------------) + I slattum 0x002baa85, // n0x1827 c0x0000 (---------------) + I smola 0x00221ec6, // n0x1828 c0x0000 (---------------) + I snaase 0x0035bc85, // n0x1829 c0x0000 (---------------) + I snasa 0x002b558a, // n0x182a c0x0000 (---------------) + I snillfjord 0x00349886, // n0x182b c0x0000 (---------------) + I snoasa 0x0022c387, // n0x182c c0x0000 (---------------) + I sogndal 0x002b6445, // n0x182d c0x0000 (---------------) + I sogne 0x002d1dc7, // n0x182e c0x0000 (---------------) + I sokndal 0x002d9ac4, // n0x182f c0x0000 (---------------) + I sola 0x002dba46, // n0x1830 c0x0000 (---------------) + I solund 0x00357045, // n0x1831 c0x0000 (---------------) + I somna 0x00205bcb, // n0x1832 c0x0000 (---------------) + I sondre-land 0x0024e609, // n0x1833 c0x0000 (---------------) + I songdalen 0x0036780a, // n0x1834 c0x0000 (---------------) + I sor-aurdal 0x00266288, // n0x1835 c0x0000 (---------------) + I sor-fron 0x0030e648, // n0x1836 c0x0000 (---------------) + I sor-odal 0x002e85cc, // n0x1837 c0x0000 (---------------) + I sor-varanger 0x002e8e07, // n0x1838 c0x0000 (---------------) + I sorfold 0x002f1688, // n0x1839 c0x0000 (---------------) + I sorreisa 0x002f4088, // n0x183a c0x0000 (---------------) + I sortland 0x002f7fc5, // n0x183b c0x0000 (---------------) + I sorum 0x002b83ca, // n0x183c c0x0000 (---------------) + I spjelkavik 0x003278c9, // n0x183d c0x0000 (---------------) + I spydeberg 0x40e01942, // n0x183e c0x0103 (n0x1962-n0x1963) + I st 0x00201946, // n0x183f c0x0000 (---------------) + I stange 0x00209d84, // n0x1840 c0x0000 (---------------) + I stat 0x002d77c9, // n0x1841 c0x0000 (---------------) + I stathelle 0x0024b689, // n0x1842 c0x0000 (---------------) + I stavanger 0x0021a587, // n0x1843 c0x0000 (---------------) + I stavern 0x00249f47, // n0x1844 c0x0000 (---------------) + I steigen 0x00276309, // n0x1845 c0x0000 (---------------) + I steinkjer 0x00393e08, // n0x1846 c0x0000 (---------------) + I stjordal 0x00393e0f, // n0x1847 c0x0000 (---------------) + I stjordalshalsen 0x002674c6, // n0x1848 c0x0000 (---------------) + I stokke 0x0023cb0b, // n0x1849 c0x0000 (---------------) + I stor-elvdal 0x003601c5, // n0x184a c0x0000 (---------------) + I stord 0x003601c7, // n0x184b c0x0000 (---------------) + I stordal 0x0038a709, // n0x184c c0x0000 (---------------) + I storfjord 0x00237ac6, // n0x184d c0x0000 (---------------) + I strand 0x00237ac7, // n0x184e c0x0000 (---------------) + I stranda 0x00308bc5, // n0x184f c0x0000 (---------------) + I stryn 0x002310c4, // n0x1850 c0x0000 (---------------) + I sula 0x002a8986, // n0x1851 c0x0000 (---------------) + I suldal 0x002119c4, // n0x1852 c0x0000 (---------------) + I sund 0x00301107, // n0x1853 c0x0000 (---------------) + I sunndal 0x002e1788, // n0x1854 c0x0000 (---------------) + I surnadal 0x412e34c8, // n0x1855 c0x0104 (n0x1963-n0x1964) + I svalbard 0x002e3ac5, // n0x1856 c0x0000 (---------------) + I sveio 0x002e3c07, // n0x1857 c0x0000 (---------------) + I svelvik 0x00299549, // n0x1858 c0x0000 (---------------) + I sykkylven 0x00208004, // n0x1859 c0x0000 (---------------) + I tana 0x00208008, // n0x185a c0x0000 (---------------) + I tananger 0x41645f88, // n0x185b c0x0105 (n0x1964-n0x1966) o I telemark 0x00218144, // n0x185c c0x0000 (---------------) + I time 0x00231a08, // n0x185d c0x0000 (---------------) + I tingvoll 0x00309484, // n0x185e c0x0000 (---------------) + I tinn 0x002649c9, // n0x185f c0x0000 (---------------) + I tjeldsund 0x00399945, // n0x1860 c0x0000 (---------------) + I tjome 0x41a00142, // n0x1861 c0x0106 (n0x1966-n0x1967) + I tm 0x00267505, // n0x1862 c0x0000 (---------------) + I tokke 0x0021cd05, // n0x1863 c0x0000 (---------------) + I tolga 0x00359d08, // n0x1864 c0x0000 (---------------) + I tonsberg 0x00233407, // n0x1865 c0x0000 (---------------) + I torsken 0x41e02b82, // n0x1866 c0x0107 (n0x1967-n0x1968) + I tr 0x002c5745, // n0x1867 c0x0000 (---------------) + I trana 0x0026f306, // n0x1868 c0x0000 (---------------) + I tranby 0x0028df06, // n0x1869 c0x0000 (---------------) + I tranoy 0x002f0b48, // n0x186a c0x0000 (---------------) + I troandin 0x002f4fc8, // n0x186b c0x0000 (---------------) + I trogstad 0x00311a06, // n0x186c c0x0000 (---------------) + I tromsa 0x0031af46, // n0x186d c0x0000 (---------------) + I tromso 0x00367e09, // n0x186e c0x0000 (---------------) + I trondheim 0x00352d46, // n0x186f c0x0000 (---------------) + I trysil 0x00286a8b, // n0x1870 c0x0000 (---------------) + I tvedestrand 0x00397d85, // n0x1871 c0x0000 (---------------) + I tydal 0x0021f006, // n0x1872 c0x0000 (---------------) + I tynset 0x0022d288, // n0x1873 c0x0000 (---------------) + I tysfjord 0x0022f806, // n0x1874 c0x0000 (---------------) + I tysnes 0x002263c6, // n0x1875 c0x0000 (---------------) + I tysvar 0x0020d14a, // n0x1876 c0x0000 (---------------) + I ullensaker 0x00283a0a, // n0x1877 c0x0000 (---------------) + I ullensvang 0x00284905, // n0x1878 c0x0000 (---------------) + I ulvik 0x002c3c47, // n0x1879 c0x0000 (---------------) + I unjarga 0x0033f3c6, // n0x187a c0x0000 (---------------) + I utsira 0x422000c2, // n0x187b c0x0108 (n0x1968-n0x1969) + I va 0x002cc507, // n0x187c c0x0000 (---------------) + I vaapste 0x0026df45, // n0x187d c0x0000 (---------------) + I vadso 0x00238644, // n0x187e c0x0000 (---------------) + I vaga 0x00238645, // n0x187f c0x0000 (---------------) + I vagan 0x003107c6, // n0x1880 c0x0000 (---------------) + I vagsoy 0x00322c07, // n0x1881 c0x0000 (---------------) + I vaksdal 0x002175c5, // n0x1882 c0x0000 (---------------) + I valle 0x0024b744, // n0x1883 c0x0000 (---------------) + I vang 0x0025cdc8, // n0x1884 c0x0000 (---------------) + I vanylven 0x00226485, // n0x1885 c0x0000 (---------------) + I vardo 0x0039d047, // n0x1886 c0x0000 (---------------) + I varggat 0x0028c4c5, // n0x1887 c0x0000 (---------------) + I varoy 0x00215ac5, // n0x1888 c0x0000 (---------------) + I vefsn 0x00332784, // n0x1889 c0x0000 (---------------) + I vega 0x00332789, // n0x188a c0x0000 (---------------) + I vegarshei 0x002db4c8, // n0x188b c0x0000 (---------------) + I vennesla 0x0036e606, // n0x188c c0x0000 (---------------) + I verdal 0x0033f9c6, // n0x188d c0x0000 (---------------) + I verran 0x00217e46, // n0x188e c0x0000 (---------------) + I vestby 0x427966c8, // n0x188f c0x0109 (n0x1969-n0x196a) o I vestfold 0x002e8447, // n0x1890 c0x0000 (---------------) + I vestnes 0x002e88cd, // n0x1891 c0x0000 (---------------) + I vestre-slidre 0x002e8fcc, // n0x1892 c0x0000 (---------------) + I vestre-toten 0x002e95c9, // n0x1893 c0x0000 (---------------) + I vestvagoy 0x002e9809, // n0x1894 c0x0000 (---------------) + I vevelstad 0x42b4be42, // n0x1895 c0x010a (n0x196a-n0x196b) + I vf 0x00394f83, // n0x1896 c0x0000 (---------------) + I vgs 0x0020ddc3, // n0x1897 c0x0000 (---------------) + I vik 0x0024e845, // n0x1898 c0x0000 (---------------) + I vikna 0x0037ce4a, // n0x1899 c0x0000 (---------------) + I vindafjord 0x003118c6, // n0x189a c0x0000 (---------------) + I voagat 0x002ef605, // n0x189b c0x0000 (---------------) + I volda 0x002f39c4, // n0x189c c0x0000 (---------------) + I voss 0x002f39cb, // n0x189d c0x0000 (---------------) + I vossevangen 0x00306c4c, // n0x189e c0x0000 (---------------) + I xn--andy-ira 0x0030748c, // n0x189f c0x0000 (---------------) + I xn--asky-ira 0x00307795, // n0x18a0 c0x0000 (---------------) + I xn--aurskog-hland-jnb 0x0030a1cd, // n0x18a1 c0x0000 (---------------) + I xn--avery-yua 0x0030bc8f, // n0x18a2 c0x0000 (---------------) + I xn--bdddj-mrabd 0x0030c052, // n0x18a3 c0x0000 (---------------) + I xn--bearalvhki-y4a 0x0030c4cf, // n0x18a4 c0x0000 (---------------) + I xn--berlevg-jxa 0x0030c892, // n0x18a5 c0x0000 (---------------) + I xn--bhcavuotna-s4a 0x0030cd13, // n0x18a6 c0x0000 (---------------) + I xn--bhccavuotna-k7a 0x0030d1cd, // n0x18a7 c0x0000 (---------------) + I xn--bidr-5nac 0x0030d78d, // n0x18a8 c0x0000 (---------------) + I xn--bievt-0qa 0x0030db0e, // n0x18a9 c0x0000 (---------------) + I xn--bjarky-fya 0x0030dfce, // n0x18aa c0x0000 (---------------) + I xn--bjddar-pta 0x0030e84c, // n0x18ab c0x0000 (---------------) + I xn--blt-elab 0x0030ebcc, // n0x18ac c0x0000 (---------------) + I xn--bmlo-gra 0x0030f00b, // n0x18ad c0x0000 (---------------) + I xn--bod-2na 0x0030f38e, // n0x18ae c0x0000 (---------------) + I xn--brnny-wuac 0x00310dd2, // n0x18af c0x0000 (---------------) + I xn--brnnysund-m8ac 0x0031168c, // n0x18b0 c0x0000 (---------------) + I xn--brum-voa 0x00311dd0, // n0x18b1 c0x0000 (---------------) + I xn--btsfjord-9za 0x003202d2, // n0x18b2 c0x0000 (---------------) + I xn--davvenjrga-y4a 0x0032118c, // n0x18b3 c0x0000 (---------------) + I xn--dnna-gra 0x0032184d, // n0x18b4 c0x0000 (---------------) + I xn--drbak-wua 0x00321b8c, // n0x18b5 c0x0000 (---------------) + I xn--dyry-ira 0x00323751, // n0x18b6 c0x0000 (---------------) + I xn--eveni-0qa01ga 0x0032470d, // n0x18b7 c0x0000 (---------------) + I xn--finny-yua 0x00327b0d, // n0x18b8 c0x0000 (---------------) + I xn--fjord-lra 0x0032810a, // n0x18b9 c0x0000 (---------------) + I xn--fl-zia 0x0032838c, // n0x18ba c0x0000 (---------------) + I xn--flor-jra 0x00328c8c, // n0x18bb c0x0000 (---------------) + I xn--frde-gra 0x0032920c, // n0x18bc c0x0000 (---------------) + I xn--frna-woa 0x00329a8c, // n0x18bd c0x0000 (---------------) + I xn--frya-hra 0x0032e093, // n0x18be c0x0000 (---------------) + I xn--ggaviika-8ya47h 0x0032e990, // n0x18bf c0x0000 (---------------) + I xn--gildeskl-g0a 0x0032ed90, // n0x18c0 c0x0000 (---------------) + I xn--givuotna-8ya 0x0033060d, // n0x18c1 c0x0000 (---------------) + I xn--gjvik-wua 0x00330c0c, // n0x18c2 c0x0000 (---------------) + I xn--gls-elac 0x00331809, // n0x18c3 c0x0000 (---------------) + I xn--h-2fa 0x0033470d, // n0x18c4 c0x0000 (---------------) + I xn--hbmer-xqa 0x00334a53, // n0x18c5 c0x0000 (---------------) + I xn--hcesuolo-7ya35b 0x0033add1, // n0x18c6 c0x0000 (---------------) + I xn--hgebostad-g3a 0x0033b213, // n0x18c7 c0x0000 (---------------) + I xn--hmmrfeasta-s4ac 0x0033d00f, // n0x18c8 c0x0000 (---------------) + I xn--hnefoss-q1a 0x0033d3cc, // n0x18c9 c0x0000 (---------------) + I xn--hobl-ira 0x0033d6cf, // n0x18ca c0x0000 (---------------) + I xn--holtlen-hxa 0x0033da8d, // n0x18cb c0x0000 (---------------) + I xn--hpmir-xqa 0x0033e08f, // n0x18cc c0x0000 (---------------) + I xn--hyanger-q1a 0x0033e450, // n0x18cd c0x0000 (---------------) + I xn--hylandet-54a 0x0033eece, // n0x18ce c0x0000 (---------------) + I xn--indery-fya 0x0034328e, // n0x18cf c0x0000 (---------------) + I xn--jlster-bya 0x003439d0, // n0x18d0 c0x0000 (---------------) + I xn--jrpeland-54a 0x00344c0d, // n0x18d1 c0x0000 (---------------) + I xn--karmy-yua 0x0034558e, // n0x18d2 c0x0000 (---------------) + I xn--kfjord-iua 0x0034590c, // n0x18d3 c0x0000 (---------------) + I xn--klbu-woa 0x003468d3, // n0x18d4 c0x0000 (---------------) + I xn--koluokta-7ya57h 0x0034870e, // n0x18d5 c0x0000 (---------------) + I xn--krager-gya 0x0034a390, // n0x18d6 c0x0000 (---------------) + I xn--kranghke-b0a 0x0034a791, // n0x18d7 c0x0000 (---------------) + I xn--krdsherad-m8a 0x0034abcf, // n0x18d8 c0x0000 (---------------) + I xn--krehamn-dxa 0x0034af93, // n0x18d9 c0x0000 (---------------) + I xn--krjohka-hwab49j 0x0034b9cd, // n0x18da c0x0000 (---------------) + I xn--ksnes-uua 0x0034bd0f, // n0x18db c0x0000 (---------------) + I xn--kvfjord-nxa 0x0034c0ce, // n0x18dc c0x0000 (---------------) + I xn--kvitsy-fya 0x0034c810, // n0x18dd c0x0000 (---------------) + I xn--kvnangen-k0a 0x0034cc09, // n0x18de c0x0000 (---------------) + I xn--l-1fa 0x0034f610, // n0x18df c0x0000 (---------------) + I xn--laheadju-7ya 0x0034fc4f, // n0x18e0 c0x0000 (---------------) + I xn--langevg-jxa 0x003502cf, // n0x18e1 c0x0000 (---------------) + I xn--ldingen-q1a 0x00350692, // n0x18e2 c0x0000 (---------------) + I xn--leagaviika-52b 0x00350f4e, // n0x18e3 c0x0000 (---------------) + I xn--lesund-hua 0x0035184d, // n0x18e4 c0x0000 (---------------) + I xn--lgrd-poac 0x0035248d, // n0x18e5 c0x0000 (---------------) + I xn--lhppi-xqa 0x003527cd, // n0x18e6 c0x0000 (---------------) + I xn--linds-pra 0x0035448d, // n0x18e7 c0x0000 (---------------) + I xn--loabt-0qa 0x003547cd, // n0x18e8 c0x0000 (---------------) + I xn--lrdal-sra 0x00354b10, // n0x18e9 c0x0000 (---------------) + I xn--lrenskog-54a 0x00354f0b, // n0x18ea c0x0000 (---------------) + I xn--lt-liac 0x0035548c, // n0x18eb c0x0000 (---------------) + I xn--lten-gra 0x0035580c, // n0x18ec c0x0000 (---------------) + I xn--lury-ira 0x00355b0c, // n0x18ed c0x0000 (---------------) + I xn--mely-ira 0x00355e0e, // n0x18ee c0x0000 (---------------) + I xn--merker-kua 0x003621d0, // n0x18ef c0x0000 (---------------) + I xn--mjndalen-64a 0x00364092, // n0x18f0 c0x0000 (---------------) + I xn--mlatvuopmi-s4a 0x0036450b, // n0x18f1 c0x0000 (---------------) + I xn--mli-tla 0x00364f8e, // n0x18f2 c0x0000 (---------------) + I xn--mlselv-iua 0x0036530e, // n0x18f3 c0x0000 (---------------) + I xn--moreke-jua 0x0036600e, // n0x18f4 c0x0000 (---------------) + I xn--mosjen-eya 0x0036818b, // n0x18f5 c0x0000 (---------------) + I xn--mot-tla 0x42f68756, // n0x18f6 c0x010b (n0x196b-n0x196d) o I xn--mre-og-romsdal-qqb 0x0036970d, // n0x18f7 c0x0000 (---------------) + I xn--msy-ula0h 0x0036a314, // n0x18f8 c0x0000 (---------------) + I xn--mtta-vrjjat-k7af 0x0036af8d, // n0x18f9 c0x0000 (---------------) + I xn--muost-0qa 0x0036c195, // n0x18fa c0x0000 (---------------) + I xn--nmesjevuemie-tcba 0x0036d58d, // n0x18fb c0x0000 (---------------) + I xn--nry-yla5g 0x0036df0f, // n0x18fc c0x0000 (---------------) + I xn--nttery-byae 0x0036e78f, // n0x18fd c0x0000 (---------------) + I xn--nvuotna-hwa 0x0037114f, // n0x18fe c0x0000 (---------------) + I xn--oppegrd-ixa 0x0037150e, // n0x18ff c0x0000 (---------------) + I xn--ostery-fya 0x0037270d, // n0x1900 c0x0000 (---------------) + I xn--osyro-wua 0x003742d1, // n0x1901 c0x0000 (---------------) + I xn--porsgu-sta26f 0x0037654c, // n0x1902 c0x0000 (---------------) + I xn--rady-ira 0x0037684c, // n0x1903 c0x0000 (---------------) + I xn--rdal-poa 0x00376b4b, // n0x1904 c0x0000 (---------------) + I xn--rde-ula 0x0037710c, // n0x1905 c0x0000 (---------------) + I xn--rdy-0nab 0x003774cf, // n0x1906 c0x0000 (---------------) + I xn--rennesy-v1a 0x00377892, // n0x1907 c0x0000 (---------------) + I xn--rhkkervju-01af 0x0037824d, // n0x1908 c0x0000 (---------------) + I xn--rholt-mra 0x0037920c, // n0x1909 c0x0000 (---------------) + I xn--risa-5na 0x0037968c, // n0x190a c0x0000 (---------------) + I xn--risr-ira 0x0037998d, // n0x190b c0x0000 (---------------) + I xn--rland-uua 0x00379ccf, // n0x190c c0x0000 (---------------) + I xn--rlingen-mxa 0x0037a08e, // n0x190d c0x0000 (---------------) + I xn--rmskog-bya 0x0037cb0c, // n0x190e c0x0000 (---------------) + I xn--rros-gra 0x0037d0cd, // n0x190f c0x0000 (---------------) + I xn--rskog-uua 0x0037d40b, // n0x1910 c0x0000 (---------------) + I xn--rst-0na 0x0037d9cc, // n0x1911 c0x0000 (---------------) + I xn--rsta-fra 0x0037df4d, // n0x1912 c0x0000 (---------------) + I xn--ryken-vua 0x0037e28e, // n0x1913 c0x0000 (---------------) + I xn--ryrvik-bya 0x0037e709, // n0x1914 c0x0000 (---------------) + I xn--s-1fa 0x0037f6d3, // n0x1915 c0x0000 (---------------) + I xn--sandnessjen-ogb 0x0038034d, // n0x1916 c0x0000 (---------------) + I xn--sandy-yua 0x0038068d, // n0x1917 c0x0000 (---------------) + I xn--seral-lra 0x00380c8c, // n0x1918 c0x0000 (---------------) + I xn--sgne-gra 0x0038110e, // n0x1919 c0x0000 (---------------) + I xn--skierv-uta 0x00382a4f, // n0x191a c0x0000 (---------------) + I xn--skjervy-v1a 0x00382e0c, // n0x191b c0x0000 (---------------) + I xn--skjk-soa 0x0038310d, // n0x191c c0x0000 (---------------) + I xn--sknit-yqa 0x0038344f, // n0x191d c0x0000 (---------------) + I xn--sknland-fxa 0x0038380c, // n0x191e c0x0000 (---------------) + I xn--slat-5na 0x00383f0c, // n0x191f c0x0000 (---------------) + I xn--slt-elab 0x003842cc, // n0x1920 c0x0000 (---------------) + I xn--smla-hra 0x003845cc, // n0x1921 c0x0000 (---------------) + I xn--smna-gra 0x00384c8d, // n0x1922 c0x0000 (---------------) + I xn--snase-nra 0x00384fd2, // n0x1923 c0x0000 (---------------) + I xn--sndre-land-0cb 0x0038564c, // n0x1924 c0x0000 (---------------) + I xn--snes-poa 0x0038594c, // n0x1925 c0x0000 (---------------) + I xn--snsa-roa 0x00385c51, // n0x1926 c0x0000 (---------------) + I xn--sr-aurdal-l8a 0x0038608f, // n0x1927 c0x0000 (---------------) + I xn--sr-fron-q1a 0x0038644f, // n0x1928 c0x0000 (---------------) + I xn--sr-odal-q1a 0x00386813, // n0x1929 c0x0000 (---------------) + I xn--sr-varanger-ggb 0x003880ce, // n0x192a c0x0000 (---------------) + I xn--srfold-bya 0x0038864f, // n0x192b c0x0000 (---------------) + I xn--srreisa-q1a 0x00388a0c, // n0x192c c0x0000 (---------------) + I xn--srum-gra 0x43388d4e, // n0x192d c0x010c (n0x196d-n0x196e) o I xn--stfold-9xa 0x003890cf, // n0x192e c0x0000 (---------------) + I xn--stjrdal-s1a 0x00389496, // n0x192f c0x0000 (---------------) + I xn--stjrdalshalsen-sqb 0x0038a292, // n0x1930 c0x0000 (---------------) + I xn--stre-toten-zcb 0x0038b84c, // n0x1931 c0x0000 (---------------) + I xn--tjme-hra 0x0038cf0f, // n0x1932 c0x0000 (---------------) + I xn--tnsberg-q1a 0x0038d58d, // n0x1933 c0x0000 (---------------) + I xn--trany-yua 0x0038d8cf, // n0x1934 c0x0000 (---------------) + I xn--trgstad-r1a 0x0038dc8c, // n0x1935 c0x0000 (---------------) + I xn--trna-woa 0x0038df8d, // n0x1936 c0x0000 (---------------) + I xn--troms-zua 0x0038e2cd, // n0x1937 c0x0000 (---------------) + I xn--tysvr-vra 0x0038f7ce, // n0x1938 c0x0000 (---------------) + I xn--unjrga-rta 0x00390f0c, // n0x1939 c0x0000 (---------------) + I xn--vads-jra 0x0039120c, // n0x193a c0x0000 (---------------) + I xn--vard-jra 0x00391510, // n0x193b c0x0000 (---------------) + I xn--vegrshei-c0a 0x00394411, // n0x193c c0x0000 (---------------) + I xn--vestvgy-ixa6o 0x0039484b, // n0x193d c0x0000 (---------------) + I xn--vg-yiab 0x00394b8c, // n0x193e c0x0000 (---------------) + I xn--vgan-qoa 0x00394e8e, // n0x193f c0x0000 (---------------) + I xn--vgsy-qoa0j 0x00396bd1, // n0x1940 c0x0000 (---------------) + I xn--vre-eiker-k8a 0x0039700e, // n0x1941 c0x0000 (---------------) + I xn--vrggt-xqad 0x0039738d, // n0x1942 c0x0000 (---------------) + I xn--vry-yla5g 0x0039e28b, // n0x1943 c0x0000 (---------------) + I xn--yer-zna 0x0039eb8f, // n0x1944 c0x0000 (---------------) + I xn--ygarden-p1a 0x003a0094, // n0x1945 c0x0000 (---------------) + I xn--ystre-slidre-ujb 0x0028fbc2, // n0x1946 c0x0000 (---------------) + I gs 0x0028fbc2, // n0x1947 c0x0000 (---------------) + I gs 0x00201e03, // n0x1948 c0x0000 (---------------) + I nes 0x0028fbc2, // n0x1949 c0x0000 (---------------) + I gs 0x00201e03, // n0x194a c0x0000 (---------------) + I nes 0x0028fbc2, // n0x194b c0x0000 (---------------) + I gs 0x00209a82, // n0x194c c0x0000 (---------------) + I os 0x0035f245, // n0x194d c0x0000 (---------------) + I valer 0x003968cc, // n0x194e c0x0000 (---------------) + I xn--vler-qoa 0x0028fbc2, // n0x194f c0x0000 (---------------) + I gs 0x0028fbc2, // n0x1950 c0x0000 (---------------) + I gs 0x00209a82, // n0x1951 c0x0000 (---------------) + I os 0x0028fbc2, // n0x1952 c0x0000 (---------------) + I gs 0x0028c2c5, // n0x1953 c0x0000 (---------------) + I heroy 0x00342a05, // n0x1954 c0x0000 (---------------) + I sande 0x0028fbc2, // n0x1955 c0x0000 (---------------) + I gs 0x0028fbc2, // n0x1956 c0x0000 (---------------) + I gs 0x0020c182, // n0x1957 c0x0000 (---------------) + I bo 0x0028c2c5, // n0x1958 c0x0000 (---------------) + I heroy 0x0030a709, // n0x1959 c0x0000 (---------------) + I xn--b-5ga 0x0033aacc, // n0x195a c0x0000 (---------------) + I xn--hery-ira 0x0028fbc2, // n0x195b c0x0000 (---------------) + I gs 0x0028fbc2, // n0x195c c0x0000 (---------------) + I gs 0x0028fbc2, // n0x195d c0x0000 (---------------) + I gs 0x0028fbc2, // n0x195e c0x0000 (---------------) + I gs 0x0035f245, // n0x195f c0x0000 (---------------) + I valer 0x0028fbc2, // n0x1960 c0x0000 (---------------) + I gs 0x0028fbc2, // n0x1961 c0x0000 (---------------) + I gs 0x0028fbc2, // n0x1962 c0x0000 (---------------) + I gs 0x0028fbc2, // n0x1963 c0x0000 (---------------) + I gs 0x0020c182, // n0x1964 c0x0000 (---------------) + I bo 0x0030a709, // n0x1965 c0x0000 (---------------) + I xn--b-5ga 0x0028fbc2, // n0x1966 c0x0000 (---------------) + I gs 0x0028fbc2, // n0x1967 c0x0000 (---------------) + I gs 0x0028fbc2, // n0x1968 c0x0000 (---------------) + I gs 0x00342a05, // n0x1969 c0x0000 (---------------) + I sande 0x0028fbc2, // n0x196a c0x0000 (---------------) + I gs 0x00342a05, // n0x196b c0x0000 (---------------) + I sande 0x0033aacc, // n0x196c c0x0000 (---------------) + I xn--hery-ira 0x003968cc, // n0x196d c0x0000 (---------------) + I xn--vler-qoa 0x00325b83, // n0x196e c0x0000 (---------------) + I biz 0x0022d0c3, // n0x196f c0x0000 (---------------) + I com 0x002325c3, // n0x1970 c0x0000 (---------------) + I edu 0x00264783, // n0x1971 c0x0000 (---------------) + I gov 0x003a4f84, // n0x1972 c0x0000 (---------------) + I info 0x0021e283, // n0x1973 c0x0000 (---------------) + I net 0x00223a43, // n0x1974 c0x0000 (---------------) + I org 0x00138d08, // n0x1975 c0x0000 (---------------) + merseine 0x000a28c4, // n0x1976 c0x0000 (---------------) + mine 0x000f2908, // n0x1977 c0x0000 (---------------) + shacknet 0x00203982, // n0x1978 c0x0000 (---------------) + I ac 0x44203dc2, // n0x1979 c0x0110 (n0x1988-n0x1989) + I co 0x0023ee03, // n0x197a c0x0000 (---------------) + I cri 0x002433c4, // n0x197b c0x0000 (---------------) + I geek 0x00206943, // n0x197c c0x0000 (---------------) + I gen 0x0033f884, // n0x197d c0x0000 (---------------) + I govt 0x00366f06, // n0x197e c0x0000 (---------------) + I health 0x0020a883, // n0x197f c0x0000 (---------------) + I iwi 0x002e2b84, // n0x1980 c0x0000 (---------------) + I kiwi 0x00268c85, // n0x1981 c0x0000 (---------------) + I maori 0x00214d03, // n0x1982 c0x0000 (---------------) + I mil 0x0021e283, // n0x1983 c0x0000 (---------------) + I net 0x00223a43, // n0x1984 c0x0000 (---------------) + I org 0x0026f0ca, // n0x1985 c0x0000 (---------------) + I parliament 0x00381f46, // n0x1986 c0x0000 (---------------) + I school 0x0036568c, // n0x1987 c0x0000 (---------------) + I xn--mori-qsa 0x000f4e08, // n0x1988 c0x0000 (---------------) + blogspot 0x00203dc2, // n0x1989 c0x0000 (---------------) + I co 0x0022d0c3, // n0x198a c0x0000 (---------------) + I com 0x002325c3, // n0x198b c0x0000 (---------------) + I edu 0x00264783, // n0x198c c0x0000 (---------------) + I gov 0x00220d43, // n0x198d c0x0000 (---------------) + I med 0x002ca1c6, // n0x198e c0x0000 (---------------) + I museum 0x0021e283, // n0x198f c0x0000 (---------------) + I net 0x00223a43, // n0x1990 c0x0000 (---------------) + I org 0x00220443, // n0x1991 c0x0000 (---------------) + I pro 0x00003142, // n0x1992 c0x0000 (---------------) + ae 0x00025387, // n0x1993 c0x0000 (---------------) + blogdns 0x000cd9c8, // n0x1994 c0x0000 (---------------) + blogsite 0x0000b54e, // n0x1995 c0x0000 (---------------) + bmoattachments 0x000822d2, // n0x1996 c0x0000 (---------------) + boldlygoingnowhere 0x44e36505, // n0x1997 c0x0113 (n0x19cf-n0x19d1) o I cdn77 0x45315d4c, // n0x1998 c0x0114 (n0x19d1-n0x19d2) o I cdn77-secure 0x001480c8, // n0x1999 c0x0000 (---------------) + dnsalias 0x000749c7, // n0x199a c0x0000 (---------------) + dnsdojo 0x0000cdcb, // n0x199b c0x0000 (---------------) + doesntexist 0x00165b89, // n0x199c c0x0000 (---------------) + dontexist 0x00147fc7, // n0x199d c0x0000 (---------------) + doomdns 0x001a2cc7, // n0x199e c0x0000 (---------------) + dsmynas 0x000748c7, // n0x199f c0x0000 (---------------) + duckdns 0x0001a106, // n0x19a0 c0x0000 (---------------) + dvrdns 0x00189b08, // n0x19a1 c0x0000 (---------------) + dynalias 0x45820b06, // n0x19a2 c0x0116 (n0x19d3-n0x19d5) + dyndns 0x000a2acd, // n0x19a3 c0x0000 (---------------) + endofinternet 0x00102310, // n0x19a4 c0x0000 (---------------) + endoftheinternet 0x45c25c02, // n0x19a5 c0x0117 (n0x19d5-n0x1a0c) + eu 0x001a2b48, // n0x19a6 c0x0000 (---------------) + familyds 0x00062887, // n0x19a7 c0x0000 (---------------) + from-me 0x00090189, // n0x19a8 c0x0000 (---------------) + game-host 0x00051786, // n0x19a9 c0x0000 (---------------) + gotdns 0x0000f882, // n0x19aa c0x0000 (---------------) + hk 0x0014904a, // n0x19ab c0x0000 (---------------) + hobby-site 0x00020cc7, // n0x19ac c0x0000 (---------------) + homedns 0x00141e07, // n0x19ad c0x0000 (---------------) + homeftp 0x0009f749, // n0x19ae c0x0000 (---------------) + homelinux 0x000a0bc8, // n0x19af c0x0000 (---------------) + homeunix 0x000d974e, // n0x19b0 c0x0000 (---------------) + is-a-bruinsfan 0x0000b1ce, // n0x19b1 c0x0000 (---------------) + is-a-candidate 0x0001118f, // n0x19b2 c0x0000 (---------------) + is-a-celticsfan 0x00011709, // n0x19b3 c0x0000 (---------------) + is-a-chef 0x00043289, // n0x19b4 c0x0000 (---------------) + is-a-geek 0x0005eccb, // n0x19b5 c0x0000 (---------------) + is-a-knight 0x0006d08f, // n0x19b6 c0x0000 (---------------) + is-a-linux-user 0x0013298c, // n0x19b7 c0x0000 (---------------) + is-a-patsfan 0x000a36cb, // n0x19b8 c0x0000 (---------------) + is-a-soxfan 0x000b3e08, // n0x19b9 c0x0000 (---------------) + is-found 0x00149cc7, // n0x19ba c0x0000 (---------------) + is-lost 0x000f1dc8, // n0x19bb c0x0000 (---------------) + is-saved 0x000e628b, // n0x19bc c0x0000 (---------------) + is-very-bad 0x000ec94c, // n0x19bd c0x0000 (---------------) + is-very-evil 0x0011514c, // n0x19be c0x0000 (---------------) + is-very-good 0x0013128c, // n0x19bf c0x0000 (---------------) + is-very-nice 0x0013fe4d, // n0x19c0 c0x0000 (---------------) + is-very-sweet 0x000fdf48, // n0x19c1 c0x0000 (---------------) + isa-geek 0x0014d5c9, // n0x19c2 c0x0000 (---------------) + kicks-ass 0x00175dcb, // n0x19c3 c0x0000 (---------------) + misconfused 0x000d67c7, // n0x19c4 c0x0000 (---------------) + podzone 0x000cd84a, // n0x19c5 c0x0000 (---------------) + readmyblog 0x000636c6, // n0x19c6 c0x0000 (---------------) + selfip 0x00091bcd, // n0x19c7 c0x0000 (---------------) + sellsyourhome 0x000c7008, // n0x19c8 c0x0000 (---------------) + servebbs 0x0006ef08, // n0x19c9 c0x0000 (---------------) + serveftp 0x0016e2c9, // n0x19ca c0x0000 (---------------) + servegame 0x000e0e0c, // n0x19cb c0x0000 (---------------) + stuff-4-sale 0x00001102, // n0x19cc c0x0000 (---------------) + us 0x001374c6, // n0x19cd c0x0000 (---------------) + webhop 0x0000a182, // n0x19ce c0x0000 (---------------) + za 0x00000301, // n0x19cf c0x0000 (---------------) + c 0x0002bd43, // n0x19d0 c0x0000 (---------------) + rsc 0x4576fc06, // n0x19d1 c0x0115 (n0x19d2-n0x19d3) o I origin 0x00036683, // n0x19d2 c0x0000 (---------------) + ssl 0x00000702, // n0x19d3 c0x0000 (---------------) + go 0x00020cc4, // n0x19d4 c0x0000 (---------------) + home 0x000001c2, // n0x19d5 c0x0000 (---------------) + al 0x000c7fc4, // n0x19d6 c0x0000 (---------------) + asso 0x00000102, // n0x19d7 c0x0000 (---------------) + at 0x00004202, // n0x19d8 c0x0000 (---------------) + au 0x00002e82, // n0x19d9 c0x0000 (---------------) + be 0x000fb3c2, // n0x19da c0x0000 (---------------) + bg 0x00000302, // n0x19db c0x0000 (---------------) + ca 0x00036502, // n0x19dc c0x0000 (---------------) + cd 0x00002302, // n0x19dd c0x0000 (---------------) + ch 0x00019ec2, // n0x19de c0x0000 (---------------) + cn 0x000362c2, // n0x19df c0x0000 (---------------) + cy 0x00035182, // n0x19e0 c0x0000 (---------------) + cz 0x00000402, // n0x19e1 c0x0000 (---------------) + de 0x000677c2, // n0x19e2 c0x0000 (---------------) + dk 0x000325c3, // n0x19e3 c0x0000 (---------------) + edu 0x00003502, // n0x19e4 c0x0000 (---------------) + ee 0x000013c2, // n0x19e5 c0x0000 (---------------) + es 0x00003a42, // n0x19e6 c0x0000 (---------------) + fi 0x00035842, // n0x19e7 c0x0000 (---------------) + fr 0x000008c2, // n0x19e8 c0x0000 (---------------) + gr 0x00031342, // n0x19e9 c0x0000 (---------------) + hr 0x00022f82, // n0x19ea c0x0000 (---------------) + hu 0x00000042, // n0x19eb c0x0000 (---------------) + ie 0x00001b02, // n0x19ec c0x0000 (---------------) + il 0x00002082, // n0x19ed c0x0000 (---------------) + in 0x00067a43, // n0x19ee c0x0000 (---------------) + int 0x000011c2, // n0x19ef c0x0000 (---------------) + is 0x00002742, // n0x19f0 c0x0000 (---------------) + it 0x000a8442, // n0x19f1 c0x0000 (---------------) + jp 0x00007b42, // n0x19f2 c0x0000 (---------------) + kr 0x00000d82, // n0x19f3 c0x0000 (---------------) + lt 0x00002ac2, // n0x19f4 c0x0000 (---------------) + lu 0x0000dd82, // n0x19f5 c0x0000 (---------------) + lv 0x00018742, // n0x19f6 c0x0000 (---------------) + mc 0x00009502, // n0x19f7 c0x0000 (---------------) + me 0x001626c2, // n0x19f8 c0x0000 (---------------) + mk 0x000643c2, // n0x19f9 c0x0000 (---------------) + mt 0x00065142, // n0x19fa c0x0000 (---------------) + my 0x0001e283, // n0x19fb c0x0000 (---------------) + net 0x000006c2, // n0x19fc c0x0000 (---------------) + ng 0x00003842, // n0x19fd c0x0000 (---------------) + nl 0x00000842, // n0x19fe c0x0000 (---------------) + no 0x00010a42, // n0x19ff c0x0000 (---------------) + nz 0x00066185, // n0x1a00 c0x0000 (---------------) + paris 0x00007502, // n0x1a01 c0x0000 (---------------) + pl 0x0006ae82, // n0x1a02 c0x0000 (---------------) + pt 0x0003d1c3, // n0x1a03 c0x0000 (---------------) + q-a 0x00000f82, // n0x1a04 c0x0000 (---------------) + ro 0x0000efc2, // n0x1a05 c0x0000 (---------------) + ru 0x00001242, // n0x1a06 c0x0000 (---------------) + se 0x00009802, // n0x1a07 c0x0000 (---------------) + si 0x00008882, // n0x1a08 c0x0000 (---------------) + sk 0x00002b82, // n0x1a09 c0x0000 (---------------) + tr 0x00000bc2, // n0x1a0a c0x0000 (---------------) + uk 0x00001102, // n0x1a0b c0x0000 (---------------) + us 0x00212703, // n0x1a0c c0x0000 (---------------) + I abo 0x00203982, // n0x1a0d c0x0000 (---------------) + I ac 0x0022d0c3, // n0x1a0e c0x0000 (---------------) + I com 0x002325c3, // n0x1a0f c0x0000 (---------------) + I edu 0x00210ec3, // n0x1a10 c0x0000 (---------------) + I gob 0x0020ab83, // n0x1a11 c0x0000 (---------------) + I ing 0x00220d43, // n0x1a12 c0x0000 (---------------) + I med 0x0021e283, // n0x1a13 c0x0000 (---------------) + I net 0x0020f543, // n0x1a14 c0x0000 (---------------) + I nom 0x00223a43, // n0x1a15 c0x0000 (---------------) + I org 0x0028c203, // n0x1a16 c0x0000 (---------------) + I sld 0x000f4e08, // n0x1a17 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x1a18 c0x0000 (---------------) + I com 0x002325c3, // n0x1a19 c0x0000 (---------------) + I edu 0x00210ec3, // n0x1a1a c0x0000 (---------------) + I gob 0x00214d03, // n0x1a1b c0x0000 (---------------) + I mil 0x0021e283, // n0x1a1c c0x0000 (---------------) + I net 0x0020f543, // n0x1a1d c0x0000 (---------------) + I nom 0x00223a43, // n0x1a1e c0x0000 (---------------) + I org 0x0022d0c3, // n0x1a1f c0x0000 (---------------) + I com 0x002325c3, // n0x1a20 c0x0000 (---------------) + I edu 0x00223a43, // n0x1a21 c0x0000 (---------------) + I org 0x0022d0c3, // n0x1a22 c0x0000 (---------------) + I com 0x002325c3, // n0x1a23 c0x0000 (---------------) + I edu 0x00264783, // n0x1a24 c0x0000 (---------------) + I gov 0x00200041, // n0x1a25 c0x0000 (---------------) + I i 0x00214d03, // n0x1a26 c0x0000 (---------------) + I mil 0x0021e283, // n0x1a27 c0x0000 (---------------) + I net 0x002006c3, // n0x1a28 c0x0000 (---------------) + I ngo 0x00223a43, // n0x1a29 c0x0000 (---------------) + I org 0x00325b83, // n0x1a2a c0x0000 (---------------) + I biz 0x0022d0c3, // n0x1a2b c0x0000 (---------------) + I com 0x002325c3, // n0x1a2c c0x0000 (---------------) + I edu 0x00281083, // n0x1a2d c0x0000 (---------------) + I fam 0x00210ec3, // n0x1a2e c0x0000 (---------------) + I gob 0x0022e8c3, // n0x1a2f c0x0000 (---------------) + I gok 0x00247843, // n0x1a30 c0x0000 (---------------) + I gon 0x0029d043, // n0x1a31 c0x0000 (---------------) + I gop 0x00247083, // n0x1a32 c0x0000 (---------------) + I gos 0x00264783, // n0x1a33 c0x0000 (---------------) + I gov 0x003a4f84, // n0x1a34 c0x0000 (---------------) + I info 0x0021e283, // n0x1a35 c0x0000 (---------------) + I net 0x00223a43, // n0x1a36 c0x0000 (---------------) + I org 0x002292c3, // n0x1a37 c0x0000 (---------------) + I web 0x00326104, // n0x1a38 c0x0000 (---------------) + I agro 0x00223cc3, // n0x1a39 c0x0000 (---------------) + I aid 0x00003b03, // n0x1a3a c0x0000 (---------------) + art 0x00200103, // n0x1a3b c0x0000 (---------------) + I atm 0x00395808, // n0x1a3c c0x0000 (---------------) + I augustow 0x0021dc84, // n0x1a3d c0x0000 (---------------) + I auto 0x0033c14a, // n0x1a3e c0x0000 (---------------) + I babia-gora 0x003981c6, // n0x1a3f c0x0000 (---------------) + I bedzin 0x003899c7, // n0x1a40 c0x0000 (---------------) + I beskidy 0x0021d28a, // n0x1a41 c0x0000 (---------------) + I bialowieza 0x00267389, // n0x1a42 c0x0000 (---------------) + I bialystok 0x0039be87, // n0x1a43 c0x0000 (---------------) + I bielawa 0x003a198a, // n0x1a44 c0x0000 (---------------) + I bieszczady 0x00325b83, // n0x1a45 c0x0000 (---------------) + I biz 0x00371f0b, // n0x1a46 c0x0000 (---------------) + I boleslawiec 0x0038ca89, // n0x1a47 c0x0000 (---------------) + I bydgoszcz 0x00217f45, // n0x1a48 c0x0000 (---------------) + I bytom 0x002c7907, // n0x1a49 c0x0000 (---------------) + I cieszyn 0x00003dc2, // n0x1a4a c0x0000 (---------------) + co 0x0022d0c3, // n0x1a4b c0x0000 (---------------) + I com 0x00256887, // n0x1a4c c0x0000 (---------------) + I czeladz 0x00367b45, // n0x1a4d c0x0000 (---------------) + I czest 0x002b6b09, // n0x1a4e c0x0000 (---------------) + I dlugoleka 0x002325c3, // n0x1a4f c0x0000 (---------------) + I edu 0x00221c46, // n0x1a50 c0x0000 (---------------) + I elblag 0x002b5243, // n0x1a51 c0x0000 (---------------) + I elk 0x0004e6c3, // n0x1a52 c0x0000 (---------------) + gda 0x000f2d46, // n0x1a53 c0x0000 (---------------) + gdansk 0x0013a546, // n0x1a54 c0x0000 (---------------) + gdynia 0x0000a807, // n0x1a55 c0x0000 (---------------) + gliwice 0x0020ea46, // n0x1a56 c0x0000 (---------------) + I glogow 0x00211cc5, // n0x1a57 c0x0000 (---------------) + I gmina 0x0023a247, // n0x1a58 c0x0000 (---------------) + I gniezno 0x003298c7, // n0x1a59 c0x0000 (---------------) + I gorlice 0x47a64783, // n0x1a5a c0x011e (n0x1add-n0x1b0c) + I gov 0x003213c7, // n0x1a5b c0x0000 (---------------) + I grajewo 0x00358ac3, // n0x1a5c c0x0000 (---------------) + I gsm 0x002c1fc5, // n0x1a5d c0x0000 (---------------) + I ilawa 0x003a4f84, // n0x1a5e c0x0000 (---------------) + I info 0x002b0bc8, // n0x1a5f c0x0000 (---------------) + I jaworzno 0x002a790c, // n0x1a60 c0x0000 (---------------) + I jelenia-gora 0x002a6cc5, // n0x1a61 c0x0000 (---------------) + I jgora 0x0031c986, // n0x1a62 c0x0000 (---------------) + I kalisz 0x00256747, // n0x1a63 c0x0000 (---------------) + I karpacz 0x003938c7, // n0x1a64 c0x0000 (---------------) + I kartuzy 0x00209f87, // n0x1a65 c0x0000 (---------------) + I kaszuby 0x0020b988, // n0x1a66 c0x0000 (---------------) + I katowice 0x0024614f, // n0x1a67 c0x0000 (---------------) + I kazimierz-dolny 0x0026b685, // n0x1a68 c0x0000 (---------------) + I kepno 0x0023ef07, // n0x1a69 c0x0000 (---------------) + I ketrzyn 0x002070c7, // n0x1a6a c0x0000 (---------------) + I klodzko 0x0029e5ca, // n0x1a6b c0x0000 (---------------) + I kobierzyce 0x00286389, // n0x1a6c c0x0000 (---------------) + I kolobrzeg 0x002c5405, // n0x1a6d c0x0000 (---------------) + I konin 0x002c844a, // n0x1a6e c0x0000 (---------------) + I konskowola 0x00137386, // n0x1a6f c0x0000 (---------------) + krakow 0x002b52c5, // n0x1a70 c0x0000 (---------------) + I kutno 0x00364744, // n0x1a71 c0x0000 (---------------) + I lapy 0x003954c6, // n0x1a72 c0x0000 (---------------) + I lebork 0x0032c547, // n0x1a73 c0x0000 (---------------) + I legnica 0x0022b047, // n0x1a74 c0x0000 (---------------) + I lezajsk 0x0026a4c8, // n0x1a75 c0x0000 (---------------) + I limanowa 0x00212ac5, // n0x1a76 c0x0000 (---------------) + I lomza 0x00367a46, // n0x1a77 c0x0000 (---------------) + I lowicz 0x00387145, // n0x1a78 c0x0000 (---------------) + I lubin 0x00382085, // n0x1a79 c0x0000 (---------------) + I lukow 0x00224ec4, // n0x1a7a c0x0000 (---------------) + I mail 0x002e6687, // n0x1a7b c0x0000 (---------------) + I malbork 0x003030ca, // n0x1a7c c0x0000 (---------------) + I malopolska 0x002043c8, // n0x1a7d c0x0000 (---------------) + I mazowsze 0x002e27c6, // n0x1a7e c0x0000 (---------------) + I mazury 0x00020d43, // n0x1a7f c0x0000 (---------------) + med 0x003a15c5, // n0x1a80 c0x0000 (---------------) + I media 0x0022ad06, // n0x1a81 c0x0000 (---------------) + I miasta 0x003a0886, // n0x1a82 c0x0000 (---------------) + I mielec 0x0031a486, // n0x1a83 c0x0000 (---------------) + I mielno 0x00214d03, // n0x1a84 c0x0000 (---------------) + I mil 0x003784c7, // n0x1a85 c0x0000 (---------------) + I mragowo 0x00207045, // n0x1a86 c0x0000 (---------------) + I naklo 0x0021e283, // n0x1a87 c0x0000 (---------------) + I net 0x003085cd, // n0x1a88 c0x0000 (---------------) + I nieruchomosci 0x0020f543, // n0x1a89 c0x0000 (---------------) + I nom 0x0026a5c8, // n0x1a8a c0x0000 (---------------) + I nowaruda 0x00397c04, // n0x1a8b c0x0000 (---------------) + I nysa 0x0026fb85, // n0x1a8c c0x0000 (---------------) + I olawa 0x0029e4c6, // n0x1a8d c0x0000 (---------------) + I olecko 0x00234c46, // n0x1a8e c0x0000 (---------------) + I olkusz 0x0021ef07, // n0x1a8f c0x0000 (---------------) + I olsztyn 0x002350c7, // n0x1a90 c0x0000 (---------------) + I opoczno 0x00240f85, // n0x1a91 c0x0000 (---------------) + I opole 0x00223a43, // n0x1a92 c0x0000 (---------------) + I org 0x0039c447, // n0x1a93 c0x0000 (---------------) + I ostroda 0x002c3849, // n0x1a94 c0x0000 (---------------) + I ostroleka 0x0020c3c9, // n0x1a95 c0x0000 (---------------) + I ostrowiec 0x0020e78a, // n0x1a96 c0x0000 (---------------) + I ostrowwlkp 0x00242b02, // n0x1a97 c0x0000 (---------------) + I pc 0x002c1f84, // n0x1a98 c0x0000 (---------------) + I pila 0x002d0544, // n0x1a99 c0x0000 (---------------) + I pisz 0x00214a87, // n0x1a9a c0x0000 (---------------) + I podhale 0x0022e188, // n0x1a9b c0x0000 (---------------) + I podlasie 0x002d7249, // n0x1a9c c0x0000 (---------------) + I polkowice 0x00302109, // n0x1a9d c0x0000 (---------------) + I pomorskie 0x002d7e07, // n0x1a9e c0x0000 (---------------) + I pomorze 0x0024dfc6, // n0x1a9f c0x0000 (---------------) + I powiat 0x000d94c6, // n0x1aa0 c0x0000 (---------------) + poznan 0x002da7c4, // n0x1aa1 c0x0000 (---------------) + I priv 0x002da94a, // n0x1aa2 c0x0000 (---------------) + I prochowice 0x002ddc08, // n0x1aa3 c0x0000 (---------------) + I pruszkow 0x002de1c9, // n0x1aa4 c0x0000 (---------------) + I przeworsk 0x0028f346, // n0x1aa5 c0x0000 (---------------) + I pulawy 0x0032f605, // n0x1aa6 c0x0000 (---------------) + I radom 0x00204288, // n0x1aa7 c0x0000 (---------------) + I rawa-maz 0x002bd4ca, // n0x1aa8 c0x0000 (---------------) + I realestate 0x0027f083, // n0x1aa9 c0x0000 (---------------) + I rel 0x00333186, // n0x1aaa c0x0000 (---------------) + I rybnik 0x002d7f07, // n0x1aab c0x0000 (---------------) + I rzeszow 0x0020b885, // n0x1aac c0x0000 (---------------) + I sanok 0x00221505, // n0x1aad c0x0000 (---------------) + I sejny 0x002417c3, // n0x1aae c0x0000 (---------------) + I sex 0x00382744, // n0x1aaf c0x0000 (---------------) + I shop 0x0022a005, // n0x1ab0 c0x0000 (---------------) + I sklep 0x0027ce07, // n0x1ab1 c0x0000 (---------------) + I skoczow 0x002db605, // n0x1ab2 c0x0000 (---------------) + I slask 0x002cacc6, // n0x1ab3 c0x0000 (---------------) + I slupsk 0x000e73c5, // n0x1ab4 c0x0000 (---------------) + sopot 0x0021c103, // n0x1ab5 c0x0000 (---------------) + I sos 0x002b03c9, // n0x1ab6 c0x0000 (---------------) + I sosnowiec 0x0026f94c, // n0x1ab7 c0x0000 (---------------) + I stalowa-wola 0x0029af4c, // n0x1ab8 c0x0000 (---------------) + I starachowice 0x002c4fc8, // n0x1ab9 c0x0000 (---------------) + I stargard 0x0025eb47, // n0x1aba c0x0000 (---------------) + I suwalki 0x002e4508, // n0x1abb c0x0000 (---------------) + I swidnica 0x002e510a, // n0x1abc c0x0000 (---------------) + I swiebodzin 0x002e5a8b, // n0x1abd c0x0000 (---------------) + I swinoujscie 0x0038cbc8, // n0x1abe c0x0000 (---------------) + I szczecin 0x0031ca88, // n0x1abf c0x0000 (---------------) + I szczytno 0x00289806, // n0x1ac0 c0x0000 (---------------) + I szkola 0x00239c05, // n0x1ac1 c0x0000 (---------------) + I targi 0x0031820a, // n0x1ac2 c0x0000 (---------------) + I tarnobrzeg 0x002235c5, // n0x1ac3 c0x0000 (---------------) + I tgory 0x00200142, // n0x1ac4 c0x0000 (---------------) + I tm 0x002ba947, // n0x1ac5 c0x0000 (---------------) + I tourism 0x0029b806, // n0x1ac6 c0x0000 (---------------) + I travel 0x0034f145, // n0x1ac7 c0x0000 (---------------) + I turek 0x002e6f49, // n0x1ac8 c0x0000 (---------------) + I turystyka 0x002c1785, // n0x1ac9 c0x0000 (---------------) + I tychy 0x00281205, // n0x1aca c0x0000 (---------------) + I ustka 0x002c1b89, // n0x1acb c0x0000 (---------------) + I walbrzych 0x0022ab86, // n0x1acc c0x0000 (---------------) + I warmia 0x00289e48, // n0x1acd c0x0000 (---------------) + I warszawa 0x00253bc3, // n0x1ace c0x0000 (---------------) + I waw 0x0020bf86, // n0x1acf c0x0000 (---------------) + I wegrow 0x0026ea46, // n0x1ad0 c0x0000 (---------------) + I wielun 0x002f5345, // n0x1ad1 c0x0000 (---------------) + I wlocl 0x002f5349, // n0x1ad2 c0x0000 (---------------) + I wloclawek 0x002aaa49, // n0x1ad3 c0x0000 (---------------) + I wodzislaw 0x00242e47, // n0x1ad4 c0x0000 (---------------) + I wolomin 0x000f51c4, // n0x1ad5 c0x0000 (---------------) + wroc 0x002f51c7, // n0x1ad6 c0x0000 (---------------) + I wroclaw 0x00302009, // n0x1ad7 c0x0000 (---------------) + I zachpomor 0x0021d485, // n0x1ad8 c0x0000 (---------------) + I zagan 0x0012b788, // n0x1ad9 c0x0000 (---------------) + zakopane 0x003424c5, // n0x1ada c0x0000 (---------------) + I zarow 0x00335285, // n0x1adb c0x0000 (---------------) + I zgora 0x0021e349, // n0x1adc c0x0000 (---------------) + I zgorzelec 0x00200942, // n0x1add c0x0000 (---------------) + I ap 0x00223ac4, // n0x1ade c0x0000 (---------------) + I griw 0x00201342, // n0x1adf c0x0000 (---------------) + I ic 0x002011c2, // n0x1ae0 c0x0000 (---------------) + I is 0x00269ec5, // n0x1ae1 c0x0000 (---------------) + I kmpsp 0x002cae08, // n0x1ae2 c0x0000 (---------------) + I konsulat 0x0036bf05, // n0x1ae3 c0x0000 (---------------) + I kppsp 0x002b8303, // n0x1ae4 c0x0000 (---------------) + I kwp 0x002b8305, // n0x1ae5 c0x0000 (---------------) + I kwpsp 0x002c7cc3, // n0x1ae6 c0x0000 (---------------) + I mup 0x0020bf42, // n0x1ae7 c0x0000 (---------------) + I mw 0x00260004, // n0x1ae8 c0x0000 (---------------) + I oirm 0x002debc3, // n0x1ae9 c0x0000 (---------------) + I oum 0x00203942, // n0x1aea c0x0000 (---------------) + I pa 0x002dc144, // n0x1aeb c0x0000 (---------------) + I pinb 0x002d0b43, // n0x1aec c0x0000 (---------------) + I piw 0x00208f42, // n0x1aed c0x0000 (---------------) + I po 0x00269f43, // n0x1aee c0x0000 (---------------) + I psp 0x00285a84, // n0x1aef c0x0000 (---------------) + I psse 0x002b0103, // n0x1af0 c0x0000 (---------------) + I pup 0x0022bec4, // n0x1af1 c0x0000 (---------------) + I rzgw 0x00200642, // n0x1af2 c0x0000 (---------------) + I sa 0x00269b43, // n0x1af3 c0x0000 (---------------) + I sdn 0x00213843, // n0x1af4 c0x0000 (---------------) + I sko 0x00205bc2, // n0x1af5 c0x0000 (---------------) + I so 0x00329142, // n0x1af6 c0x0000 (---------------) + I sr 0x002aa889, // n0x1af7 c0x0000 (---------------) + I starostwo 0x002025c2, // n0x1af8 c0x0000 (---------------) + I ug 0x00282e44, // n0x1af9 c0x0000 (---------------) + I ugim 0x00204102, // n0x1afa c0x0000 (---------------) + I um 0x00204104, // n0x1afb c0x0000 (---------------) + I umig 0x0024df84, // n0x1afc c0x0000 (---------------) + I upow 0x002dcf84, // n0x1afd c0x0000 (---------------) + I uppo 0x00201102, // n0x1afe c0x0000 (---------------) + I us 0x0023d4c2, // n0x1aff c0x0000 (---------------) + I uw 0x0020f003, // n0x1b00 c0x0000 (---------------) + I uzs 0x002e5703, // n0x1b01 c0x0000 (---------------) + I wif 0x0023e504, // n0x1b02 c0x0000 (---------------) + I wiih 0x00256204, // n0x1b03 c0x0000 (---------------) + I winb 0x002c37c4, // n0x1b04 c0x0000 (---------------) + I wios 0x002c5304, // n0x1b05 c0x0000 (---------------) + I witd 0x002f4843, // n0x1b06 c0x0000 (---------------) + I wiw 0x002eafc3, // n0x1b07 c0x0000 (---------------) + I wsa 0x00337304, // n0x1b08 c0x0000 (---------------) + I wskr 0x002f6644, // n0x1b09 c0x0000 (---------------) + I wuoz 0x002f6946, // n0x1b0a c0x0000 (---------------) + I wzmiuw 0x002cf782, // n0x1b0b c0x0000 (---------------) + I zp 0x00203dc2, // n0x1b0c c0x0000 (---------------) + I co 0x002325c3, // n0x1b0d c0x0000 (---------------) + I edu 0x00264783, // n0x1b0e c0x0000 (---------------) + I gov 0x0021e283, // n0x1b0f c0x0000 (---------------) + I net 0x00223a43, // n0x1b10 c0x0000 (---------------) + I org 0x00203982, // n0x1b11 c0x0000 (---------------) + I ac 0x00325b83, // n0x1b12 c0x0000 (---------------) + I biz 0x0022d0c3, // n0x1b13 c0x0000 (---------------) + I com 0x002325c3, // n0x1b14 c0x0000 (---------------) + I edu 0x00201903, // n0x1b15 c0x0000 (---------------) + I est 0x00264783, // n0x1b16 c0x0000 (---------------) + I gov 0x003a4f84, // n0x1b17 c0x0000 (---------------) + I info 0x002aab44, // n0x1b18 c0x0000 (---------------) + I isla 0x0020ff84, // n0x1b19 c0x0000 (---------------) + I name 0x0021e283, // n0x1b1a c0x0000 (---------------) + I net 0x00223a43, // n0x1b1b c0x0000 (---------------) + I org 0x00220443, // n0x1b1c c0x0000 (---------------) + I pro 0x002db004, // n0x1b1d c0x0000 (---------------) + I prof 0x002adac3, // n0x1b1e c0x0000 (---------------) + I aca 0x00202903, // n0x1b1f c0x0000 (---------------) + I bar 0x00217203, // n0x1b20 c0x0000 (---------------) + I cpa 0x00203603, // n0x1b21 c0x0000 (---------------) + I eng 0x002a9503, // n0x1b22 c0x0000 (---------------) + I jur 0x00266983, // n0x1b23 c0x0000 (---------------) + I law 0x00220d43, // n0x1b24 c0x0000 (---------------) + I med 0x0022d0c3, // n0x1b25 c0x0000 (---------------) + I com 0x002325c3, // n0x1b26 c0x0000 (---------------) + I edu 0x00264783, // n0x1b27 c0x0000 (---------------) + I gov 0x0021e283, // n0x1b28 c0x0000 (---------------) + I net 0x00223a43, // n0x1b29 c0x0000 (---------------) + I org 0x002d3403, // n0x1b2a c0x0000 (---------------) + I plo 0x0022f683, // n0x1b2b c0x0000 (---------------) + I sec 0x000f4e08, // n0x1b2c c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x1b2d c0x0000 (---------------) + I com 0x002325c3, // n0x1b2e c0x0000 (---------------) + I edu 0x00264783, // n0x1b2f c0x0000 (---------------) + I gov 0x00267a43, // n0x1b30 c0x0000 (---------------) + I int 0x0021e283, // n0x1b31 c0x0000 (---------------) + I net 0x0023c444, // n0x1b32 c0x0000 (---------------) + I nome 0x00223a43, // n0x1b33 c0x0000 (---------------) + I org 0x00297d84, // n0x1b34 c0x0000 (---------------) + I publ 0x002cb085, // n0x1b35 c0x0000 (---------------) + I belau 0x00203dc2, // n0x1b36 c0x0000 (---------------) + I co 0x002003c2, // n0x1b37 c0x0000 (---------------) + I ed 0x00200702, // n0x1b38 c0x0000 (---------------) + I go 0x00201e02, // n0x1b39 c0x0000 (---------------) + I ne 0x00200282, // n0x1b3a c0x0000 (---------------) + I or 0x0022d0c3, // n0x1b3b c0x0000 (---------------) + I com 0x00235044, // n0x1b3c c0x0000 (---------------) + I coop 0x002325c3, // n0x1b3d c0x0000 (---------------) + I edu 0x00264783, // n0x1b3e c0x0000 (---------------) + I gov 0x00214d03, // n0x1b3f c0x0000 (---------------) + I mil 0x0021e283, // n0x1b40 c0x0000 (---------------) + I net 0x00223a43, // n0x1b41 c0x0000 (---------------) + I org 0x000f4e08, // n0x1b42 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x1b43 c0x0000 (---------------) + I com 0x002325c3, // n0x1b44 c0x0000 (---------------) + I edu 0x00264783, // n0x1b45 c0x0000 (---------------) + I gov 0x00214d03, // n0x1b46 c0x0000 (---------------) + I mil 0x0020ff84, // n0x1b47 c0x0000 (---------------) + I name 0x0021e283, // n0x1b48 c0x0000 (---------------) + I net 0x00223a43, // n0x1b49 c0x0000 (---------------) + I org 0x00213403, // n0x1b4a c0x0000 (---------------) + I sch 0x002c7fc4, // n0x1b4b c0x0000 (---------------) + I asso 0x000f4e08, // n0x1b4c c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x1b4d c0x0000 (---------------) + I com 0x0020f543, // n0x1b4e c0x0000 (---------------) + I nom 0x00244d04, // n0x1b4f c0x0000 (---------------) + I arts 0x000f4e08, // n0x1b50 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x1b51 c0x0000 (---------------) + I com 0x00246bc4, // n0x1b52 c0x0000 (---------------) + I firm 0x003a4f84, // n0x1b53 c0x0000 (---------------) + I info 0x0020f543, // n0x1b54 c0x0000 (---------------) + I nom 0x00204982, // n0x1b55 c0x0000 (---------------) + I nt 0x00223a43, // n0x1b56 c0x0000 (---------------) + I org 0x00226e03, // n0x1b57 c0x0000 (---------------) + I rec 0x003758c5, // n0x1b58 c0x0000 (---------------) + I store 0x00200142, // n0x1b59 c0x0000 (---------------) + I tm 0x002f6783, // n0x1b5a c0x0000 (---------------) + I www 0x00203982, // n0x1b5b c0x0000 (---------------) + I ac 0x000f4e08, // n0x1b5c c0x0000 (---------------) + blogspot 0x00203dc2, // n0x1b5d c0x0000 (---------------) + I co 0x002325c3, // n0x1b5e c0x0000 (---------------) + I edu 0x00264783, // n0x1b5f c0x0000 (---------------) + I gov 0x00202082, // n0x1b60 c0x0000 (---------------) + I in 0x00223a43, // n0x1b61 c0x0000 (---------------) + I org 0x00203982, // n0x1b62 c0x0000 (---------------) + I ac 0x003a1b47, // n0x1b63 c0x0000 (---------------) + I adygeya 0x0027c805, // n0x1b64 c0x0000 (---------------) + I altai 0x00289c84, // n0x1b65 c0x0000 (---------------) + I amur 0x00376206, // n0x1b66 c0x0000 (---------------) + I amursk 0x0023044b, // n0x1b67 c0x0000 (---------------) + I arkhangelsk 0x00253949, // n0x1b68 c0x0000 (---------------) + I astrakhan 0x0031c8c6, // n0x1b69 c0x0000 (---------------) + I baikal 0x0031e689, // n0x1b6a c0x0000 (---------------) + I bashkiria 0x002b2708, // n0x1b6b c0x0000 (---------------) + I belgorod 0x00204f83, // n0x1b6c c0x0000 (---------------) + I bir 0x000f4e08, // n0x1b6d c0x0000 (---------------) + blogspot 0x00225707, // n0x1b6e c0x0000 (---------------) + I bryansk 0x00349408, // n0x1b6f c0x0000 (---------------) + I buryatia 0x0033a8c3, // n0x1b70 c0x0000 (---------------) + I cbg 0x00245944, // n0x1b71 c0x0000 (---------------) + I chel 0x0025dbcb, // n0x1b72 c0x0000 (---------------) + I chelyabinsk 0x002a6e85, // n0x1b73 c0x0000 (---------------) + I chita 0x002b73c8, // n0x1b74 c0x0000 (---------------) + I chukotka 0x0032a089, // n0x1b75 c0x0000 (---------------) + I chuvashia 0x00256183, // n0x1b76 c0x0000 (---------------) + I cmw 0x0022d0c3, // n0x1b77 c0x0000 (---------------) + I com 0x00201848, // n0x1b78 c0x0000 (---------------) + I dagestan 0x002e3687, // n0x1b79 c0x0000 (---------------) + I dudinka 0x00338a86, // n0x1b7a c0x0000 (---------------) + I e-burg 0x002325c3, // n0x1b7b c0x0000 (---------------) + I edu 0x0037e8c7, // n0x1b7c c0x0000 (---------------) + I fareast 0x00264783, // n0x1b7d c0x0000 (---------------) + I gov 0x002fa586, // n0x1b7e c0x0000 (---------------) + I grozny 0x00267a43, // n0x1b7f c0x0000 (---------------) + I int 0x00229ec7, // n0x1b80 c0x0000 (---------------) + I irkutsk 0x0026aac7, // n0x1b81 c0x0000 (---------------) + I ivanovo 0x0037fb87, // n0x1b82 c0x0000 (---------------) + I izhevsk 0x002e6605, // n0x1b83 c0x0000 (---------------) + I jamal 0x00207683, // n0x1b84 c0x0000 (---------------) + I jar 0x0020f7cb, // n0x1b85 c0x0000 (---------------) + I joshkar-ola 0x00369488, // n0x1b86 c0x0000 (---------------) + I k-uralsk 0x00265088, // n0x1b87 c0x0000 (---------------) + I kalmykia 0x00249846, // n0x1b88 c0x0000 (---------------) + I kaluga 0x002186c9, // n0x1b89 c0x0000 (---------------) + I kamchatka 0x00319547, // n0x1b8a c0x0000 (---------------) + I karelia 0x002ef945, // n0x1b8b c0x0000 (---------------) + I kazan 0x00372284, // n0x1b8c c0x0000 (---------------) + I kchr 0x002675c8, // n0x1b8d c0x0000 (---------------) + I kemerovo 0x0022b2ca, // n0x1b8e c0x0000 (---------------) + I khabarovsk 0x0022b509, // n0x1b8f c0x0000 (---------------) + I khakassia 0x0025cd43, // n0x1b90 c0x0000 (---------------) + I khv 0x00278085, // n0x1b91 c0x0000 (---------------) + I kirov 0x0032e6c3, // n0x1b92 c0x0000 (---------------) + I kms 0x0029bfc6, // n0x1b93 c0x0000 (---------------) + I koenig 0x002cff44, // n0x1b94 c0x0000 (---------------) + I komi 0x002f2e88, // n0x1b95 c0x0000 (---------------) + I kostroma 0x0037fd0b, // n0x1b96 c0x0000 (---------------) + I krasnoyarsk 0x0032e585, // n0x1b97 c0x0000 (---------------) + I kuban 0x002b2486, // n0x1b98 c0x0000 (---------------) + I kurgan 0x002b4145, // n0x1b99 c0x0000 (---------------) + I kursk 0x002b4688, // n0x1b9a c0x0000 (---------------) + I kustanai 0x002b5407, // n0x1b9b c0x0000 (---------------) + I kuzbass 0x00208747, // n0x1b9c c0x0000 (---------------) + I lipetsk 0x0033ca47, // n0x1b9d c0x0000 (---------------) + I magadan 0x00218044, // n0x1b9e c0x0000 (---------------) + I mari 0x0021d747, // n0x1b9f c0x0000 (---------------) + I mari-el 0x00273c46, // n0x1ba0 c0x0000 (---------------) + I marine 0x00214d03, // n0x1ba1 c0x0000 (---------------) + I mil 0x002c0588, // n0x1ba2 c0x0000 (---------------) + I mordovia 0x0024c843, // n0x1ba3 c0x0000 (---------------) + I msk 0x002c8288, // n0x1ba4 c0x0000 (---------------) + I murmansk 0x002ccf05, // n0x1ba5 c0x0000 (---------------) + I mytis 0x00309088, // n0x1ba6 c0x0000 (---------------) + I nakhodka 0x002327c7, // n0x1ba7 c0x0000 (---------------) + I nalchik 0x0021e283, // n0x1ba8 c0x0000 (---------------) + I net 0x00319c43, // n0x1ba9 c0x0000 (---------------) + I nkz 0x0039cf84, // n0x1baa c0x0000 (---------------) + I nnov 0x0036f287, // n0x1bab c0x0000 (---------------) + I norilsk 0x002069c3, // n0x1bac c0x0000 (---------------) + I nov 0x0026ab8b, // n0x1bad c0x0000 (---------------) + I novosibirsk 0x00213803, // n0x1bae c0x0000 (---------------) + I nsk 0x0024c804, // n0x1baf c0x0000 (---------------) + I omsk 0x00375948, // n0x1bb0 c0x0000 (---------------) + I orenburg 0x00223a43, // n0x1bb1 c0x0000 (---------------) + I org 0x002d0e85, // n0x1bb2 c0x0000 (---------------) + I oryol 0x0028f945, // n0x1bb3 c0x0000 (---------------) + I oskol 0x00206f46, // n0x1bb4 c0x0000 (---------------) + I palana 0x002109c5, // n0x1bb5 c0x0000 (---------------) + I penza 0x002cd2c4, // n0x1bb6 c0x0000 (---------------) + I perm 0x00203902, // n0x1bb7 c0x0000 (---------------) + I pp 0x002de483, // n0x1bb8 c0x0000 (---------------) + I ptz 0x003647ca, // n0x1bb9 c0x0000 (---------------) + I pyatigorsk 0x002707c3, // n0x1bba c0x0000 (---------------) + I rnd 0x002cbdc9, // n0x1bbb c0x0000 (---------------) + I rubtsovsk 0x00237206, // n0x1bbc c0x0000 (---------------) + I ryazan 0x002169c8, // n0x1bbd c0x0000 (---------------) + I sakhalin 0x002855c6, // n0x1bbe c0x0000 (---------------) + I samara 0x0021a247, // n0x1bbf c0x0000 (---------------) + I saratov 0x002bf608, // n0x1bc0 c0x0000 (---------------) + I simbirsk 0x002ed448, // n0x1bc1 c0x0000 (---------------) + I smolensk 0x002cf703, // n0x1bc2 c0x0000 (---------------) + I snz 0x00269f83, // n0x1bc3 c0x0000 (---------------) + I spb 0x0021ff49, // n0x1bc4 c0x0000 (---------------) + I stavropol 0x00286a43, // n0x1bc5 c0x0000 (---------------) + I stv 0x0033f2c6, // n0x1bc6 c0x0000 (---------------) + I surgut 0x0027c486, // n0x1bc7 c0x0000 (---------------) + I syzran 0x0030e2c6, // n0x1bc8 c0x0000 (---------------) + I tambov 0x0039c149, // n0x1bc9 c0x0000 (---------------) + I tatarstan 0x002f4c44, // n0x1bca c0x0000 (---------------) + I test 0x00204ac3, // n0x1bcb c0x0000 (---------------) + I tom 0x00369385, // n0x1bcc c0x0000 (---------------) + I tomsk 0x002eb389, // n0x1bcd c0x0000 (---------------) + I tsaritsyn 0x00208843, // n0x1bce c0x0000 (---------------) + I tsk 0x00356f04, // n0x1bcf c0x0000 (---------------) + I tula 0x002e7f84, // n0x1bd0 c0x0000 (---------------) + I tuva 0x0020da44, // n0x1bd1 c0x0000 (---------------) + I tver 0x00356a46, // n0x1bd2 c0x0000 (---------------) + I tyumen 0x00207843, // n0x1bd3 c0x0000 (---------------) + I udm 0x00207848, // n0x1bd4 c0x0000 (---------------) + I udmurtia 0x00253588, // n0x1bd5 c0x0000 (---------------) + I ulan-ude 0x00353b46, // n0x1bd6 c0x0000 (---------------) + I vdonsk 0x002ef74b, // n0x1bd7 c0x0000 (---------------) + I vladikavkaz 0x002efa88, // n0x1bd8 c0x0000 (---------------) + I vladimir 0x002efc8b, // n0x1bd9 c0x0000 (---------------) + I vladivostok 0x002f0489, // n0x1bda c0x0000 (---------------) + I volgograd 0x002f2c47, // n0x1bdb c0x0000 (---------------) + I vologda 0x002f3648, // n0x1bdc c0x0000 (---------------) + I voronezh 0x002f4283, // n0x1bdd c0x0000 (---------------) + I vrn 0x0037bd86, // n0x1bde c0x0000 (---------------) + I vyatka 0x002089c7, // n0x1bdf c0x0000 (---------------) + I yakutia 0x00291005, // n0x1be0 c0x0000 (---------------) + I yamal 0x00343589, // n0x1be1 c0x0000 (---------------) + I yaroslavl 0x00318d4d, // n0x1be2 c0x0000 (---------------) + I yekaterinburg 0x00216811, // n0x1be3 c0x0000 (---------------) + I yuzhno-sakhalinsk 0x00228c85, // n0x1be4 c0x0000 (---------------) + I zgrad 0x00203982, // n0x1be5 c0x0000 (---------------) + I ac 0x00203dc2, // n0x1be6 c0x0000 (---------------) + I co 0x0022d0c3, // n0x1be7 c0x0000 (---------------) + I com 0x002325c3, // n0x1be8 c0x0000 (---------------) + I edu 0x0034ec04, // n0x1be9 c0x0000 (---------------) + I gouv 0x00264783, // n0x1bea c0x0000 (---------------) + I gov 0x00267a43, // n0x1beb c0x0000 (---------------) + I int 0x00214d03, // n0x1bec c0x0000 (---------------) + I mil 0x0021e283, // n0x1bed c0x0000 (---------------) + I net 0x0022d0c3, // n0x1bee c0x0000 (---------------) + I com 0x002325c3, // n0x1bef c0x0000 (---------------) + I edu 0x00264783, // n0x1bf0 c0x0000 (---------------) + I gov 0x00220d43, // n0x1bf1 c0x0000 (---------------) + I med 0x0021e283, // n0x1bf2 c0x0000 (---------------) + I net 0x00223a43, // n0x1bf3 c0x0000 (---------------) + I org 0x00297d83, // n0x1bf4 c0x0000 (---------------) + I pub 0x00213403, // n0x1bf5 c0x0000 (---------------) + I sch 0x0022d0c3, // n0x1bf6 c0x0000 (---------------) + I com 0x002325c3, // n0x1bf7 c0x0000 (---------------) + I edu 0x00264783, // n0x1bf8 c0x0000 (---------------) + I gov 0x0021e283, // n0x1bf9 c0x0000 (---------------) + I net 0x00223a43, // n0x1bfa c0x0000 (---------------) + I org 0x0022d0c3, // n0x1bfb c0x0000 (---------------) + I com 0x002325c3, // n0x1bfc c0x0000 (---------------) + I edu 0x00264783, // n0x1bfd c0x0000 (---------------) + I gov 0x0021e283, // n0x1bfe c0x0000 (---------------) + I net 0x00223a43, // n0x1bff c0x0000 (---------------) + I org 0x0022d0c3, // n0x1c00 c0x0000 (---------------) + I com 0x002325c3, // n0x1c01 c0x0000 (---------------) + I edu 0x00264783, // n0x1c02 c0x0000 (---------------) + I gov 0x003a4f84, // n0x1c03 c0x0000 (---------------) + I info 0x00220d43, // n0x1c04 c0x0000 (---------------) + I med 0x0021e283, // n0x1c05 c0x0000 (---------------) + I net 0x00223a43, // n0x1c06 c0x0000 (---------------) + I org 0x0020da42, // n0x1c07 c0x0000 (---------------) + I tv 0x00200101, // n0x1c08 c0x0000 (---------------) + I a 0x00203982, // n0x1c09 c0x0000 (---------------) + I ac 0x00200001, // n0x1c0a c0x0000 (---------------) + I b 0x0030bd82, // n0x1c0b c0x0000 (---------------) + I bd 0x000f4e08, // n0x1c0c c0x0000 (---------------) + blogspot 0x0021b4c5, // n0x1c0d c0x0000 (---------------) + I brand 0x00200301, // n0x1c0e c0x0000 (---------------) + I c 0x0002d0c3, // n0x1c0f c0x0000 (---------------) + com 0x00200401, // n0x1c10 c0x0000 (---------------) + I d 0x00200081, // n0x1c11 c0x0000 (---------------) + I e 0x00200381, // n0x1c12 c0x0000 (---------------) + I f 0x0022b202, // n0x1c13 c0x0000 (---------------) + I fh 0x0022b204, // n0x1c14 c0x0000 (---------------) + I fhsk 0x0035f1c3, // n0x1c15 c0x0000 (---------------) + I fhv 0x00200701, // n0x1c16 c0x0000 (---------------) + I g 0x00200601, // n0x1c17 c0x0000 (---------------) + I h 0x00200041, // n0x1c18 c0x0000 (---------------) + I i 0x00200c01, // n0x1c19 c0x0000 (---------------) + I k 0x00395247, // n0x1c1a c0x0000 (---------------) + I komforb 0x0037ff8f, // n0x1c1b c0x0000 (---------------) + I kommunalforbund 0x002d1606, // n0x1c1c c0x0000 (---------------) + I komvux 0x00200201, // n0x1c1d c0x0000 (---------------) + I l 0x00261f46, // n0x1c1e c0x0000 (---------------) + I lanbib 0x00200181, // n0x1c1f c0x0000 (---------------) + I m 0x002005c1, // n0x1c20 c0x0000 (---------------) + I n 0x0030954e, // n0x1c21 c0x0000 (---------------) + I naturbruksgymn 0x00200281, // n0x1c22 c0x0000 (---------------) + I o 0x00223a43, // n0x1c23 c0x0000 (---------------) + I org 0x00200981, // n0x1c24 c0x0000 (---------------) + I p 0x00295205, // n0x1c25 c0x0000 (---------------) + I parti 0x00203902, // n0x1c26 c0x0000 (---------------) + I pp 0x002416c5, // n0x1c27 c0x0000 (---------------) + I press 0x002002c1, // n0x1c28 c0x0000 (---------------) + I r 0x00200641, // n0x1c29 c0x0000 (---------------) + I s 0x00200141, // n0x1c2a c0x0000 (---------------) + I t 0x00200142, // n0x1c2b c0x0000 (---------------) + I tm 0x00200a81, // n0x1c2c c0x0000 (---------------) + I u 0x00200d01, // n0x1c2d c0x0000 (---------------) + I w 0x002045c1, // n0x1c2e c0x0000 (---------------) + I x 0x002010c1, // n0x1c2f c0x0000 (---------------) + I y 0x00204441, // n0x1c30 c0x0000 (---------------) + I z 0x000f4e08, // n0x1c31 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x1c32 c0x0000 (---------------) + I com 0x002325c3, // n0x1c33 c0x0000 (---------------) + I edu 0x00264783, // n0x1c34 c0x0000 (---------------) + I gov 0x0021e283, // n0x1c35 c0x0000 (---------------) + I net 0x00223a43, // n0x1c36 c0x0000 (---------------) + I org 0x00220503, // n0x1c37 c0x0000 (---------------) + I per 0x0022d0c3, // n0x1c38 c0x0000 (---------------) + I com 0x00264783, // n0x1c39 c0x0000 (---------------) + I gov 0x00085ec8, // n0x1c3a c0x0000 (---------------) + hashbang 0x00214d03, // n0x1c3b c0x0000 (---------------) + I mil 0x0021e283, // n0x1c3c c0x0000 (---------------) + I net 0x00223a43, // n0x1c3d c0x0000 (---------------) + I org 0x014d1f88, // n0x1c3e c0x0005 (---------------)* o platform 0x000f4e08, // n0x1c3f c0x0000 (---------------) + blogspot 0x000f4e08, // n0x1c40 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x1c41 c0x0000 (---------------) + I com 0x002325c3, // n0x1c42 c0x0000 (---------------) + I edu 0x00264783, // n0x1c43 c0x0000 (---------------) + I gov 0x0021e283, // n0x1c44 c0x0000 (---------------) + I net 0x00223a43, // n0x1c45 c0x0000 (---------------) + I org 0x00203b03, // n0x1c46 c0x0000 (---------------) + I art 0x000f4e08, // n0x1c47 c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x1c48 c0x0000 (---------------) + I com 0x002325c3, // n0x1c49 c0x0000 (---------------) + I edu 0x0034ec04, // n0x1c4a c0x0000 (---------------) + I gouv 0x00223a43, // n0x1c4b c0x0000 (---------------) + I org 0x00291545, // n0x1c4c c0x0000 (---------------) + I perso 0x003179c4, // n0x1c4d c0x0000 (---------------) + I univ 0x0022d0c3, // n0x1c4e c0x0000 (---------------) + I com 0x0021e283, // n0x1c4f c0x0000 (---------------) + I net 0x00223a43, // n0x1c50 c0x0000 (---------------) + I org 0x00203dc2, // n0x1c51 c0x0000 (---------------) + I co 0x0022d0c3, // n0x1c52 c0x0000 (---------------) + I com 0x00231009, // n0x1c53 c0x0000 (---------------) + I consulado 0x002325c3, // n0x1c54 c0x0000 (---------------) + I edu 0x00234989, // n0x1c55 c0x0000 (---------------) + I embaixada 0x00264783, // n0x1c56 c0x0000 (---------------) + I gov 0x00214d03, // n0x1c57 c0x0000 (---------------) + I mil 0x0021e283, // n0x1c58 c0x0000 (---------------) + I net 0x00223a43, // n0x1c59 c0x0000 (---------------) + I org 0x002da5c8, // n0x1c5a c0x0000 (---------------) + I principe 0x00212847, // n0x1c5b c0x0000 (---------------) + I saotome 0x003758c5, // n0x1c5c c0x0000 (---------------) + I store 0x003a1b47, // n0x1c5d c0x0000 (---------------) + I adygeya 0x0023044b, // n0x1c5e c0x0000 (---------------) + I arkhangelsk 0x0020acc8, // n0x1c5f c0x0000 (---------------) + I balashov 0x0031e689, // n0x1c60 c0x0000 (---------------) + I bashkiria 0x00225707, // n0x1c61 c0x0000 (---------------) + I bryansk 0x00201848, // n0x1c62 c0x0000 (---------------) + I dagestan 0x002fa586, // n0x1c63 c0x0000 (---------------) + I grozny 0x0026aac7, // n0x1c64 c0x0000 (---------------) + I ivanovo 0x00265088, // n0x1c65 c0x0000 (---------------) + I kalmykia 0x00249846, // n0x1c66 c0x0000 (---------------) + I kaluga 0x00319547, // n0x1c67 c0x0000 (---------------) + I karelia 0x0022b509, // n0x1c68 c0x0000 (---------------) + I khakassia 0x00376ec9, // n0x1c69 c0x0000 (---------------) + I krasnodar 0x002b2486, // n0x1c6a c0x0000 (---------------) + I kurgan 0x002b3105, // n0x1c6b c0x0000 (---------------) + I lenug 0x002c0588, // n0x1c6c c0x0000 (---------------) + I mordovia 0x0024c843, // n0x1c6d c0x0000 (---------------) + I msk 0x002c8288, // n0x1c6e c0x0000 (---------------) + I murmansk 0x002327c7, // n0x1c6f c0x0000 (---------------) + I nalchik 0x002069c3, // n0x1c70 c0x0000 (---------------) + I nov 0x00239387, // n0x1c71 c0x0000 (---------------) + I obninsk 0x002109c5, // n0x1c72 c0x0000 (---------------) + I penza 0x002d6bc8, // n0x1c73 c0x0000 (---------------) + I pokrovsk 0x0026e005, // n0x1c74 c0x0000 (---------------) + I sochi 0x00269f83, // n0x1c75 c0x0000 (---------------) + I spb 0x00333449, // n0x1c76 c0x0000 (---------------) + I togliatti 0x002a3f47, // n0x1c77 c0x0000 (---------------) + I troitsk 0x00356f04, // n0x1c78 c0x0000 (---------------) + I tula 0x002e7f84, // n0x1c79 c0x0000 (---------------) + I tuva 0x002ef74b, // n0x1c7a c0x0000 (---------------) + I vladikavkaz 0x002efa88, // n0x1c7b c0x0000 (---------------) + I vladimir 0x002f2c47, // n0x1c7c c0x0000 (---------------) + I vologda 0x0022d0c3, // n0x1c7d c0x0000 (---------------) + I com 0x002325c3, // n0x1c7e c0x0000 (---------------) + I edu 0x00210ec3, // n0x1c7f c0x0000 (---------------) + I gob 0x00223a43, // n0x1c80 c0x0000 (---------------) + I org 0x0023b903, // n0x1c81 c0x0000 (---------------) + I red 0x00264783, // n0x1c82 c0x0000 (---------------) + I gov 0x0022d0c3, // n0x1c83 c0x0000 (---------------) + I com 0x002325c3, // n0x1c84 c0x0000 (---------------) + I edu 0x00264783, // n0x1c85 c0x0000 (---------------) + I gov 0x00214d03, // n0x1c86 c0x0000 (---------------) + I mil 0x0021e283, // n0x1c87 c0x0000 (---------------) + I net 0x00223a43, // n0x1c88 c0x0000 (---------------) + I org 0x00203982, // n0x1c89 c0x0000 (---------------) + I ac 0x00203dc2, // n0x1c8a c0x0000 (---------------) + I co 0x00223a43, // n0x1c8b c0x0000 (---------------) + I org 0x000f4e08, // n0x1c8c c0x0000 (---------------) + blogspot 0x00203982, // n0x1c8d c0x0000 (---------------) + I ac 0x00203dc2, // n0x1c8e c0x0000 (---------------) + I co 0x00200702, // n0x1c8f c0x0000 (---------------) + I go 0x00202082, // n0x1c90 c0x0000 (---------------) + I in 0x00204142, // n0x1c91 c0x0000 (---------------) + I mi 0x0021e283, // n0x1c92 c0x0000 (---------------) + I net 0x00200282, // n0x1c93 c0x0000 (---------------) + I or 0x00203982, // n0x1c94 c0x0000 (---------------) + I ac 0x00325b83, // n0x1c95 c0x0000 (---------------) + I biz 0x00203dc2, // n0x1c96 c0x0000 (---------------) + I co 0x0022d0c3, // n0x1c97 c0x0000 (---------------) + I com 0x002325c3, // n0x1c98 c0x0000 (---------------) + I edu 0x00200702, // n0x1c99 c0x0000 (---------------) + I go 0x00264783, // n0x1c9a c0x0000 (---------------) + I gov 0x00267a43, // n0x1c9b c0x0000 (---------------) + I int 0x00214d03, // n0x1c9c c0x0000 (---------------) + I mil 0x0020ff84, // n0x1c9d c0x0000 (---------------) + I name 0x0021e283, // n0x1c9e c0x0000 (---------------) + I net 0x00217843, // n0x1c9f c0x0000 (---------------) + I nic 0x00223a43, // n0x1ca0 c0x0000 (---------------) + I org 0x002f4c44, // n0x1ca1 c0x0000 (---------------) + I test 0x002292c3, // n0x1ca2 c0x0000 (---------------) + I web 0x00264783, // n0x1ca3 c0x0000 (---------------) + I gov 0x00203dc2, // n0x1ca4 c0x0000 (---------------) + I co 0x0022d0c3, // n0x1ca5 c0x0000 (---------------) + I com 0x002325c3, // n0x1ca6 c0x0000 (---------------) + I edu 0x00264783, // n0x1ca7 c0x0000 (---------------) + I gov 0x00214d03, // n0x1ca8 c0x0000 (---------------) + I mil 0x0021e283, // n0x1ca9 c0x0000 (---------------) + I net 0x0020f543, // n0x1caa c0x0000 (---------------) + I nom 0x00223a43, // n0x1cab c0x0000 (---------------) + I org 0x00319a07, // n0x1cac c0x0000 (---------------) + I agrinet 0x0022d0c3, // n0x1cad c0x0000 (---------------) + I com 0x002213c7, // n0x1cae c0x0000 (---------------) + I defense 0x002d49c6, // n0x1caf c0x0000 (---------------) + I edunet 0x0020d203, // n0x1cb0 c0x0000 (---------------) + I ens 0x00208543, // n0x1cb1 c0x0000 (---------------) + I fin 0x00264783, // n0x1cb2 c0x0000 (---------------) + I gov 0x0021c903, // n0x1cb3 c0x0000 (---------------) + I ind 0x003a4f84, // n0x1cb4 c0x0000 (---------------) + I info 0x0035a544, // n0x1cb5 c0x0000 (---------------) + I intl 0x002d1386, // n0x1cb6 c0x0000 (---------------) + I mincom 0x00218c83, // n0x1cb7 c0x0000 (---------------) + I nat 0x0021e283, // n0x1cb8 c0x0000 (---------------) + I net 0x00223a43, // n0x1cb9 c0x0000 (---------------) + I org 0x00291545, // n0x1cba c0x0000 (---------------) + I perso 0x00386d04, // n0x1cbb c0x0000 (---------------) + I rnrt 0x002df083, // n0x1cbc c0x0000 (---------------) + I rns 0x0020a5c3, // n0x1cbd c0x0000 (---------------) + I rnu 0x002ba947, // n0x1cbe c0x0000 (---------------) + I tourism 0x0032ff45, // n0x1cbf c0x0000 (---------------) + I turen 0x0022d0c3, // n0x1cc0 c0x0000 (---------------) + I com 0x002325c3, // n0x1cc1 c0x0000 (---------------) + I edu 0x00264783, // n0x1cc2 c0x0000 (---------------) + I gov 0x00214d03, // n0x1cc3 c0x0000 (---------------) + I mil 0x0021e283, // n0x1cc4 c0x0000 (---------------) + I net 0x00223a43, // n0x1cc5 c0x0000 (---------------) + I org 0x00202f82, // n0x1cc6 c0x0000 (---------------) + I av 0x002c7143, // n0x1cc7 c0x0000 (---------------) + I bbs 0x002b2703, // n0x1cc8 c0x0000 (---------------) + I bel 0x00325b83, // n0x1cc9 c0x0000 (---------------) + I biz 0x51a2d0c3, // n0x1cca c0x0146 (n0x1cdb-n0x1cdc) + I com 0x00205c82, // n0x1ccb c0x0000 (---------------) + I dr 0x002325c3, // n0x1ccc c0x0000 (---------------) + I edu 0x00206943, // n0x1ccd c0x0000 (---------------) + I gen 0x00264783, // n0x1cce c0x0000 (---------------) + I gov 0x003a4f84, // n0x1ccf c0x0000 (---------------) + I info 0x00369643, // n0x1cd0 c0x0000 (---------------) + I k12 0x0026b683, // n0x1cd1 c0x0000 (---------------) + I kep 0x00214d03, // n0x1cd2 c0x0000 (---------------) + I mil 0x0020ff84, // n0x1cd3 c0x0000 (---------------) + I name 0x51e08642, // n0x1cd4 c0x0147 (n0x1cdc-n0x1cdd) + I nc 0x0021e283, // n0x1cd5 c0x0000 (---------------) + I net 0x00223a43, // n0x1cd6 c0x0000 (---------------) + I org 0x002200c3, // n0x1cd7 c0x0000 (---------------) + I pol 0x00227983, // n0x1cd8 c0x0000 (---------------) + I tel 0x0020da42, // n0x1cd9 c0x0000 (---------------) + I tv 0x002292c3, // n0x1cda c0x0000 (---------------) + I web 0x000f4e08, // n0x1cdb c0x0000 (---------------) + blogspot 0x00264783, // n0x1cdc c0x0000 (---------------) + I gov 0x002dbdc4, // n0x1cdd c0x0000 (---------------) + I aero 0x00325b83, // n0x1cde c0x0000 (---------------) + I biz 0x00203dc2, // n0x1cdf c0x0000 (---------------) + I co 0x0022d0c3, // n0x1ce0 c0x0000 (---------------) + I com 0x00235044, // n0x1ce1 c0x0000 (---------------) + I coop 0x002325c3, // n0x1ce2 c0x0000 (---------------) + I edu 0x00264783, // n0x1ce3 c0x0000 (---------------) + I gov 0x003a4f84, // n0x1ce4 c0x0000 (---------------) + I info 0x00267a43, // n0x1ce5 c0x0000 (---------------) + I int 0x002bc1c4, // n0x1ce6 c0x0000 (---------------) + I jobs 0x00207c84, // n0x1ce7 c0x0000 (---------------) + I mobi 0x002ca1c6, // n0x1ce8 c0x0000 (---------------) + I museum 0x0020ff84, // n0x1ce9 c0x0000 (---------------) + I name 0x0021e283, // n0x1cea c0x0000 (---------------) + I net 0x00223a43, // n0x1ceb c0x0000 (---------------) + I org 0x00220443, // n0x1cec c0x0000 (---------------) + I pro 0x0029b806, // n0x1ced c0x0000 (---------------) + I travel 0x0004fe0b, // n0x1cee c0x0000 (---------------) + better-than 0x00020b06, // n0x1cef c0x0000 (---------------) + dyndns 0x0002910a, // n0x1cf0 c0x0000 (---------------) + on-the-web 0x000f434a, // n0x1cf1 c0x0000 (---------------) + worse-than 0x000f4e08, // n0x1cf2 c0x0000 (---------------) + blogspot 0x00387104, // n0x1cf3 c0x0000 (---------------) + I club 0x0022d0c3, // n0x1cf4 c0x0000 (---------------) + I com 0x00325b44, // n0x1cf5 c0x0000 (---------------) + I ebiz 0x002325c3, // n0x1cf6 c0x0000 (---------------) + I edu 0x00290184, // n0x1cf7 c0x0000 (---------------) + I game 0x00264783, // n0x1cf8 c0x0000 (---------------) + I gov 0x00310743, // n0x1cf9 c0x0000 (---------------) + I idv 0x00214d03, // n0x1cfa c0x0000 (---------------) + I mil 0x0021e283, // n0x1cfb c0x0000 (---------------) + I net 0x00223a43, // n0x1cfc c0x0000 (---------------) + I org 0x0031b7cb, // n0x1cfd c0x0000 (---------------) + I xn--czrw28b 0x0038e60a, // n0x1cfe c0x0000 (---------------) + I xn--uc0atv 0x003a0d4c, // n0x1cff c0x0000 (---------------) + I xn--zf0ao64a 0x00203982, // n0x1d00 c0x0000 (---------------) + I ac 0x00203dc2, // n0x1d01 c0x0000 (---------------) + I co 0x00200702, // n0x1d02 c0x0000 (---------------) + I go 0x0022de05, // n0x1d03 c0x0000 (---------------) + I hotel 0x003a4f84, // n0x1d04 c0x0000 (---------------) + I info 0x00209502, // n0x1d05 c0x0000 (---------------) + I me 0x00214d03, // n0x1d06 c0x0000 (---------------) + I mil 0x00207c84, // n0x1d07 c0x0000 (---------------) + I mobi 0x00201e02, // n0x1d08 c0x0000 (---------------) + I ne 0x00200282, // n0x1d09 c0x0000 (---------------) + I or 0x00213402, // n0x1d0a c0x0000 (---------------) + I sc 0x0020da42, // n0x1d0b c0x0000 (---------------) + I tv 0x00125b83, // n0x1d0c c0x0000 (---------------) + biz 0x002a56c9, // n0x1d0d c0x0000 (---------------) + I cherkassy 0x0027c308, // n0x1d0e c0x0000 (---------------) + I cherkasy 0x00264609, // n0x1d0f c0x0000 (---------------) + I chernigov 0x00275249, // n0x1d10 c0x0000 (---------------) + I chernihiv 0x00369f4a, // n0x1d11 c0x0000 (---------------) + I chernivtsi 0x0029934a, // n0x1d12 c0x0000 (---------------) + I chernovtsy 0x00204002, // n0x1d13 c0x0000 (---------------) + I ck 0x00219ec2, // n0x1d14 c0x0000 (---------------) + I cn 0x00003dc2, // n0x1d15 c0x0000 (---------------) + co 0x0022d0c3, // n0x1d16 c0x0000 (---------------) + I com 0x0020ef82, // n0x1d17 c0x0000 (---------------) + I cr 0x0023f0c6, // n0x1d18 c0x0000 (---------------) + I crimea 0x00350142, // n0x1d19 c0x0000 (---------------) + I cv 0x0021a1c2, // n0x1d1a c0x0000 (---------------) + I dn 0x002cc0ce, // n0x1d1b c0x0000 (---------------) + I dnepropetrovsk 0x00269b8e, // n0x1d1c c0x0000 (---------------) + I dnipropetrovsk 0x002750c7, // n0x1d1d c0x0000 (---------------) + I dominic 0x00313d47, // n0x1d1e c0x0000 (---------------) + I donetsk 0x002cf002, // n0x1d1f c0x0000 (---------------) + I dp 0x002325c3, // n0x1d20 c0x0000 (---------------) + I edu 0x00264783, // n0x1d21 c0x0000 (---------------) + I gov 0x00200b42, // n0x1d22 c0x0000 (---------------) + I if 0x00202082, // n0x1d23 c0x0000 (---------------) + I in 0x002356cf, // n0x1d24 c0x0000 (---------------) + I ivano-frankivsk 0x00216a42, // n0x1d25 c0x0000 (---------------) + I kh 0x00235a47, // n0x1d26 c0x0000 (---------------) + I kharkiv 0x0023ab07, // n0x1d27 c0x0000 (---------------) + I kharkov 0x00243487, // n0x1d28 c0x0000 (---------------) + I kherson 0x0024404c, // n0x1d29 c0x0000 (---------------) + I khmelnitskiy 0x00249a4c, // n0x1d2a c0x0000 (---------------) + I khmelnytskyi 0x00201cc4, // n0x1d2b c0x0000 (---------------) + I kiev 0x0027808a, // n0x1d2c c0x0000 (---------------) + I kirovograd 0x00237642, // n0x1d2d c0x0000 (---------------) + I km 0x00207b42, // n0x1d2e c0x0000 (---------------) + I kr 0x002aaf04, // n0x1d2f c0x0000 (---------------) + I krym 0x00261382, // n0x1d30 c0x0000 (---------------) + I ks 0x002b6582, // n0x1d31 c0x0000 (---------------) + I kv 0x00249c84, // n0x1d32 c0x0000 (---------------) + I kyiv 0x00217942, // n0x1d33 c0x0000 (---------------) + I lg 0x00200d82, // n0x1d34 c0x0000 (---------------) + I lt 0x002498c7, // n0x1d35 c0x0000 (---------------) + I lugansk 0x00399bc5, // n0x1d36 c0x0000 (---------------) + I lutsk 0x0020dd82, // n0x1d37 c0x0000 (---------------) + I lv 0x00235644, // n0x1d38 c0x0000 (---------------) + I lviv 0x003626c2, // n0x1d39 c0x0000 (---------------) + I mk 0x0026a948, // n0x1d3a c0x0000 (---------------) + I mykolaiv 0x0021e283, // n0x1d3b c0x0000 (---------------) + I net 0x00203008, // n0x1d3c c0x0000 (---------------) + I nikolaev 0x00204e82, // n0x1d3d c0x0000 (---------------) + I od 0x00233945, // n0x1d3e c0x0000 (---------------) + I odesa 0x0036ce46, // n0x1d3f c0x0000 (---------------) + I odessa 0x00223a43, // n0x1d40 c0x0000 (---------------) + I org 0x00207502, // n0x1d41 c0x0000 (---------------) + I pl 0x002d7487, // n0x1d42 c0x0000 (---------------) + I poltava 0x00003902, // n0x1d43 c0x0000 (---------------) + pp 0x002da805, // n0x1d44 c0x0000 (---------------) + I rivne 0x00383dc5, // n0x1d45 c0x0000 (---------------) + I rovno 0x002012c2, // n0x1d46 c0x0000 (---------------) + I rv 0x002239c2, // n0x1d47 c0x0000 (---------------) + I sb 0x0039870a, // n0x1d48 c0x0000 (---------------) + I sebastopol 0x00240e0a, // n0x1d49 c0x0000 (---------------) + I sevastopol 0x00214cc2, // n0x1d4a c0x0000 (---------------) + I sm 0x00353284, // n0x1d4b c0x0000 (---------------) + I sumy 0x00200dc2, // n0x1d4c c0x0000 (---------------) + I te 0x002c1e48, // n0x1d4d c0x0000 (---------------) + I ternopil 0x0020a142, // n0x1d4e c0x0000 (---------------) + I uz 0x00296388, // n0x1d4f c0x0000 (---------------) + I uzhgorod 0x002ec047, // n0x1d50 c0x0000 (---------------) + I vinnica 0x002ecd49, // n0x1d51 c0x0000 (---------------) + I vinnytsia 0x00202fc2, // n0x1d52 c0x0000 (---------------) + I vn 0x002f3405, // n0x1d53 c0x0000 (---------------) + I volyn 0x0027c7c5, // n0x1d54 c0x0000 (---------------) + I yalta 0x002be18b, // n0x1d55 c0x0000 (---------------) + I zaporizhzhe 0x002bebcc, // n0x1d56 c0x0000 (---------------) + I zaporizhzhia 0x00229d48, // n0x1d57 c0x0000 (---------------) + I zhitomir 0x002f37c8, // n0x1d58 c0x0000 (---------------) + I zhytomyr 0x002cf782, // n0x1d59 c0x0000 (---------------) + I zp 0x0021efc2, // n0x1d5a c0x0000 (---------------) + I zt 0x00203982, // n0x1d5b c0x0000 (---------------) + I ac 0x000f4e08, // n0x1d5c c0x0000 (---------------) + blogspot 0x00203dc2, // n0x1d5d c0x0000 (---------------) + I co 0x0022d0c3, // n0x1d5e c0x0000 (---------------) + I com 0x00200702, // n0x1d5f c0x0000 (---------------) + I go 0x00201e02, // n0x1d60 c0x0000 (---------------) + I ne 0x00200282, // n0x1d61 c0x0000 (---------------) + I or 0x00223a43, // n0x1d62 c0x0000 (---------------) + I org 0x00213402, // n0x1d63 c0x0000 (---------------) + I sc 0x00203982, // n0x1d64 c0x0000 (---------------) + I ac 0x53e03dc2, // n0x1d65 c0x014f (n0x1d6f-n0x1d70) + I co 0x54264783, // n0x1d66 c0x0150 (n0x1d70-n0x1d71) + I gov 0x00314403, // n0x1d67 c0x0000 (---------------) + I ltd 0x00209502, // n0x1d68 c0x0000 (---------------) + I me 0x0021e283, // n0x1d69 c0x0000 (---------------) + I net 0x002005c3, // n0x1d6a c0x0000 (---------------) + I nhs 0x00223a43, // n0x1d6b c0x0000 (---------------) + I org 0x002d2f03, // n0x1d6c c0x0000 (---------------) + I plc 0x002200c6, // n0x1d6d c0x0000 (---------------) + I police 0x01613403, // n0x1d6e c0x0005 (---------------)* o I sch 0x000f4e08, // n0x1d6f c0x0000 (---------------) + blogspot 0x00001247, // n0x1d70 c0x0000 (---------------) + service 0x54a01c82, // n0x1d71 c0x0152 (n0x1db0-n0x1db3) + I ak 0x54e001c2, // n0x1d72 c0x0153 (n0x1db3-n0x1db6) + I al 0x55202942, // n0x1d73 c0x0154 (n0x1db6-n0x1db9) + I ar 0x55602642, // n0x1d74 c0x0155 (n0x1db9-n0x1dbc) + I as 0x55a04402, // n0x1d75 c0x0156 (n0x1dbc-n0x1dbf) + I az 0x55e00302, // n0x1d76 c0x0157 (n0x1dbf-n0x1dc2) + I ca 0x56203dc2, // n0x1d77 c0x0158 (n0x1dc2-n0x1dc5) + I co 0x5662f482, // n0x1d78 c0x0159 (n0x1dc5-n0x1dc8) + I ct 0x56a1dfc2, // n0x1d79 c0x015a (n0x1dc8-n0x1dcb) + I dc 0x56e00402, // n0x1d7a c0x015b (n0x1dcb-n0x1dce) + I de 0x00269b83, // n0x1d7b c0x0000 (---------------) + I dni 0x00200383, // n0x1d7c c0x0000 (---------------) + I fed 0x57213582, // n0x1d7d c0x015c (n0x1dce-n0x1dd1) + I fl 0x57600c82, // n0x1d7e c0x015d (n0x1dd1-n0x1dd4) + I ga 0x57a0b102, // n0x1d7f c0x015e (n0x1dd4-n0x1dd7) + I gu 0x57e009c2, // n0x1d80 c0x015f (n0x1dd7-n0x1dd9) + I hi 0x582079c2, // n0x1d81 c0x0160 (n0x1dd9-n0x1ddc) + I ia 0x58603782, // n0x1d82 c0x0161 (n0x1ddc-n0x1ddf) + I id 0x58a01b02, // n0x1d83 c0x0162 (n0x1ddf-n0x1de2) + I il 0x58e02082, // n0x1d84 c0x0163 (n0x1de2-n0x1de5) + I in 0x000acb45, // n0x1d85 c0x0000 (---------------) + is-by 0x00222583, // n0x1d86 c0x0000 (---------------) + I isa 0x00286984, // n0x1d87 c0x0000 (---------------) + I kids 0x59261382, // n0x1d88 c0x0164 (n0x1de5-n0x1de8) + I ks 0x596306c2, // n0x1d89 c0x0165 (n0x1de8-n0x1deb) + I ky 0x59a03102, // n0x1d8a c0x0166 (n0x1deb-n0x1dee) + I la 0x0007de4b, // n0x1d8b c0x0000 (---------------) + land-4-sale 0x59e00182, // n0x1d8c c0x0167 (n0x1dee-n0x1df1) + I ma 0x5a646c82, // n0x1d8d c0x0169 (n0x1df4-n0x1df7) + I md 0x5aa09502, // n0x1d8e c0x016a (n0x1df7-n0x1dfa) + I me 0x5ae04142, // n0x1d8f c0x016b (n0x1dfa-n0x1dfd) + I mi 0x5b21e242, // n0x1d90 c0x016c (n0x1dfd-n0x1e00) + I mn 0x5b607c82, // n0x1d91 c0x016d (n0x1e00-n0x1e03) + I mo 0x5ba0bbc2, // n0x1d92 c0x016e (n0x1e03-n0x1e06) + I ms 0x5be643c2, // n0x1d93 c0x016f (n0x1e06-n0x1e09) + I mt 0x5c208642, // n0x1d94 c0x0170 (n0x1e09-n0x1e0c) + I nc 0x5c605c42, // n0x1d95 c0x0171 (n0x1e0c-n0x1e0e) + I nd 0x5ca01e02, // n0x1d96 c0x0172 (n0x1e0e-n0x1e11) + I ne 0x5ce005c2, // n0x1d97 c0x0173 (n0x1e11-n0x1e14) + I nh 0x5d201482, // n0x1d98 c0x0174 (n0x1e14-n0x1e17) + I nj 0x5d6354c2, // n0x1d99 c0x0175 (n0x1e17-n0x1e1a) + I nm 0x0035bc43, // n0x1d9a c0x0000 (---------------) + I nsn 0x5da093c2, // n0x1d9b c0x0176 (n0x1e1a-n0x1e1d) + I nv 0x5de19bc2, // n0x1d9c c0x0177 (n0x1e1d-n0x1e20) + I ny 0x5e2083c2, // n0x1d9d c0x0178 (n0x1e20-n0x1e23) + I oh 0x5e602482, // n0x1d9e c0x0179 (n0x1e23-n0x1e26) + I ok 0x5ea00282, // n0x1d9f c0x017a (n0x1e26-n0x1e29) + I or 0x5ee03942, // n0x1da0 c0x017b (n0x1e29-n0x1e2c) + I pa 0x5f2052c2, // n0x1da1 c0x017c (n0x1e2c-n0x1e2f) + I pr 0x5f605302, // n0x1da2 c0x017d (n0x1e2f-n0x1e32) + I ri 0x5fa13402, // n0x1da3 c0x017e (n0x1e32-n0x1e35) + I sc 0x5fe56cc2, // n0x1da4 c0x017f (n0x1e35-n0x1e37) + I sd 0x000e0e0c, // n0x1da5 c0x0000 (---------------) + stuff-4-sale 0x6022a482, // n0x1da6 c0x0180 (n0x1e37-n0x1e3a) + I tn 0x6066c182, // n0x1da7 c0x0181 (n0x1e3a-n0x1e3d) + I tx 0x60a08a82, // n0x1da8 c0x0182 (n0x1e3d-n0x1e40) + I ut 0x60e000c2, // n0x1da9 c0x0183 (n0x1e40-n0x1e43) + I va 0x61201302, // n0x1daa c0x0184 (n0x1e43-n0x1e46) + I vi 0x6166e582, // n0x1dab c0x0185 (n0x1e46-n0x1e49) + I vt 0x61a00d02, // n0x1dac c0x0186 (n0x1e49-n0x1e4c) + I wa 0x61e0a8c2, // n0x1dad c0x0187 (n0x1e4c-n0x1e4f) + I wi 0x6226edc2, // n0x1dae c0x0188 (n0x1e4f-n0x1e50) + I wv 0x62666a02, // n0x1daf c0x0189 (n0x1e50-n0x1e53) + I wy 0x0021e542, // n0x1db0 c0x0000 (---------------) + I cc 0x00369643, // n0x1db1 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1db2 c0x0000 (---------------) + I lib 0x0021e542, // n0x1db3 c0x0000 (---------------) + I cc 0x00369643, // n0x1db4 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1db5 c0x0000 (---------------) + I lib 0x0021e542, // n0x1db6 c0x0000 (---------------) + I cc 0x00369643, // n0x1db7 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1db8 c0x0000 (---------------) + I lib 0x0021e542, // n0x1db9 c0x0000 (---------------) + I cc 0x00369643, // n0x1dba c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dbb c0x0000 (---------------) + I lib 0x0021e542, // n0x1dbc c0x0000 (---------------) + I cc 0x00369643, // n0x1dbd c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dbe c0x0000 (---------------) + I lib 0x0021e542, // n0x1dbf c0x0000 (---------------) + I cc 0x00369643, // n0x1dc0 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dc1 c0x0000 (---------------) + I lib 0x0021e542, // n0x1dc2 c0x0000 (---------------) + I cc 0x00369643, // n0x1dc3 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dc4 c0x0000 (---------------) + I lib 0x0021e542, // n0x1dc5 c0x0000 (---------------) + I cc 0x00369643, // n0x1dc6 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dc7 c0x0000 (---------------) + I lib 0x0021e542, // n0x1dc8 c0x0000 (---------------) + I cc 0x00369643, // n0x1dc9 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dca c0x0000 (---------------) + I lib 0x0021e542, // n0x1dcb c0x0000 (---------------) + I cc 0x00369643, // n0x1dcc c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dcd c0x0000 (---------------) + I lib 0x0021e542, // n0x1dce c0x0000 (---------------) + I cc 0x00369643, // n0x1dcf c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dd0 c0x0000 (---------------) + I lib 0x0021e542, // n0x1dd1 c0x0000 (---------------) + I cc 0x00369643, // n0x1dd2 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dd3 c0x0000 (---------------) + I lib 0x0021e542, // n0x1dd4 c0x0000 (---------------) + I cc 0x00369643, // n0x1dd5 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dd6 c0x0000 (---------------) + I lib 0x0021e542, // n0x1dd7 c0x0000 (---------------) + I cc 0x00268ec3, // n0x1dd8 c0x0000 (---------------) + I lib 0x0021e542, // n0x1dd9 c0x0000 (---------------) + I cc 0x00369643, // n0x1dda c0x0000 (---------------) + I k12 0x00268ec3, // n0x1ddb c0x0000 (---------------) + I lib 0x0021e542, // n0x1ddc c0x0000 (---------------) + I cc 0x00369643, // n0x1ddd c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dde c0x0000 (---------------) + I lib 0x0021e542, // n0x1ddf c0x0000 (---------------) + I cc 0x00369643, // n0x1de0 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1de1 c0x0000 (---------------) + I lib 0x0021e542, // n0x1de2 c0x0000 (---------------) + I cc 0x00369643, // n0x1de3 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1de4 c0x0000 (---------------) + I lib 0x0021e542, // n0x1de5 c0x0000 (---------------) + I cc 0x00369643, // n0x1de6 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1de7 c0x0000 (---------------) + I lib 0x0021e542, // n0x1de8 c0x0000 (---------------) + I cc 0x00369643, // n0x1de9 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dea c0x0000 (---------------) + I lib 0x0021e542, // n0x1deb c0x0000 (---------------) + I cc 0x00369643, // n0x1dec c0x0000 (---------------) + I k12 0x00268ec3, // n0x1ded c0x0000 (---------------) + I lib 0x0021e542, // n0x1dee c0x0000 (---------------) + I cc 0x5a369643, // n0x1def c0x0168 (n0x1df1-n0x1df4) + I k12 0x00268ec3, // n0x1df0 c0x0000 (---------------) + I lib 0x002f9744, // n0x1df1 c0x0000 (---------------) + I chtr 0x0027c206, // n0x1df2 c0x0000 (---------------) + I paroch 0x002de543, // n0x1df3 c0x0000 (---------------) + I pvt 0x0021e542, // n0x1df4 c0x0000 (---------------) + I cc 0x00369643, // n0x1df5 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1df6 c0x0000 (---------------) + I lib 0x0021e542, // n0x1df7 c0x0000 (---------------) + I cc 0x00369643, // n0x1df8 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1df9 c0x0000 (---------------) + I lib 0x0021e542, // n0x1dfa c0x0000 (---------------) + I cc 0x00369643, // n0x1dfb c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dfc c0x0000 (---------------) + I lib 0x0021e542, // n0x1dfd c0x0000 (---------------) + I cc 0x00369643, // n0x1dfe c0x0000 (---------------) + I k12 0x00268ec3, // n0x1dff c0x0000 (---------------) + I lib 0x0021e542, // n0x1e00 c0x0000 (---------------) + I cc 0x00369643, // n0x1e01 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e02 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e03 c0x0000 (---------------) + I cc 0x00369643, // n0x1e04 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e05 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e06 c0x0000 (---------------) + I cc 0x00369643, // n0x1e07 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e08 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e09 c0x0000 (---------------) + I cc 0x00369643, // n0x1e0a c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e0b c0x0000 (---------------) + I lib 0x0021e542, // n0x1e0c c0x0000 (---------------) + I cc 0x00268ec3, // n0x1e0d c0x0000 (---------------) + I lib 0x0021e542, // n0x1e0e c0x0000 (---------------) + I cc 0x00369643, // n0x1e0f c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e10 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e11 c0x0000 (---------------) + I cc 0x00369643, // n0x1e12 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e13 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e14 c0x0000 (---------------) + I cc 0x00369643, // n0x1e15 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e16 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e17 c0x0000 (---------------) + I cc 0x00369643, // n0x1e18 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e19 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e1a c0x0000 (---------------) + I cc 0x00369643, // n0x1e1b c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e1c c0x0000 (---------------) + I lib 0x0021e542, // n0x1e1d c0x0000 (---------------) + I cc 0x00369643, // n0x1e1e c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e1f c0x0000 (---------------) + I lib 0x0021e542, // n0x1e20 c0x0000 (---------------) + I cc 0x00369643, // n0x1e21 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e22 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e23 c0x0000 (---------------) + I cc 0x00369643, // n0x1e24 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e25 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e26 c0x0000 (---------------) + I cc 0x00369643, // n0x1e27 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e28 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e29 c0x0000 (---------------) + I cc 0x00369643, // n0x1e2a c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e2b c0x0000 (---------------) + I lib 0x0021e542, // n0x1e2c c0x0000 (---------------) + I cc 0x00369643, // n0x1e2d c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e2e c0x0000 (---------------) + I lib 0x0021e542, // n0x1e2f c0x0000 (---------------) + I cc 0x00369643, // n0x1e30 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e31 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e32 c0x0000 (---------------) + I cc 0x00369643, // n0x1e33 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e34 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e35 c0x0000 (---------------) + I cc 0x00268ec3, // n0x1e36 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e37 c0x0000 (---------------) + I cc 0x00369643, // n0x1e38 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e39 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e3a c0x0000 (---------------) + I cc 0x00369643, // n0x1e3b c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e3c c0x0000 (---------------) + I lib 0x0021e542, // n0x1e3d c0x0000 (---------------) + I cc 0x00369643, // n0x1e3e c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e3f c0x0000 (---------------) + I lib 0x0021e542, // n0x1e40 c0x0000 (---------------) + I cc 0x00369643, // n0x1e41 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e42 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e43 c0x0000 (---------------) + I cc 0x00369643, // n0x1e44 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e45 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e46 c0x0000 (---------------) + I cc 0x00369643, // n0x1e47 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e48 c0x0000 (---------------) + I lib 0x0021e542, // n0x1e49 c0x0000 (---------------) + I cc 0x00369643, // n0x1e4a c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e4b c0x0000 (---------------) + I lib 0x0021e542, // n0x1e4c c0x0000 (---------------) + I cc 0x00369643, // n0x1e4d c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e4e c0x0000 (---------------) + I lib 0x0021e542, // n0x1e4f c0x0000 (---------------) + I cc 0x0021e542, // n0x1e50 c0x0000 (---------------) + I cc 0x00369643, // n0x1e51 c0x0000 (---------------) + I k12 0x00268ec3, // n0x1e52 c0x0000 (---------------) + I lib 0x62e2d0c3, // n0x1e53 c0x018b (n0x1e59-n0x1e5a) + I com 0x002325c3, // n0x1e54 c0x0000 (---------------) + I edu 0x00395b03, // n0x1e55 c0x0000 (---------------) + I gub 0x00214d03, // n0x1e56 c0x0000 (---------------) + I mil 0x0021e283, // n0x1e57 c0x0000 (---------------) + I net 0x00223a43, // n0x1e58 c0x0000 (---------------) + I org 0x000f4e08, // n0x1e59 c0x0000 (---------------) + blogspot 0x00203dc2, // n0x1e5a c0x0000 (---------------) + I co 0x0022d0c3, // n0x1e5b c0x0000 (---------------) + I com 0x0021e283, // n0x1e5c c0x0000 (---------------) + I net 0x00223a43, // n0x1e5d c0x0000 (---------------) + I org 0x0022d0c3, // n0x1e5e c0x0000 (---------------) + I com 0x002325c3, // n0x1e5f c0x0000 (---------------) + I edu 0x00264783, // n0x1e60 c0x0000 (---------------) + I gov 0x00214d03, // n0x1e61 c0x0000 (---------------) + I mil 0x0021e283, // n0x1e62 c0x0000 (---------------) + I net 0x00223a43, // n0x1e63 c0x0000 (---------------) + I org 0x00244d04, // n0x1e64 c0x0000 (---------------) + I arts 0x00203dc2, // n0x1e65 c0x0000 (---------------) + I co 0x0022d0c3, // n0x1e66 c0x0000 (---------------) + I com 0x00300643, // n0x1e67 c0x0000 (---------------) + I e12 0x002325c3, // n0x1e68 c0x0000 (---------------) + I edu 0x00246bc4, // n0x1e69 c0x0000 (---------------) + I firm 0x00210ec3, // n0x1e6a c0x0000 (---------------) + I gob 0x00264783, // n0x1e6b c0x0000 (---------------) + I gov 0x003a4f84, // n0x1e6c c0x0000 (---------------) + I info 0x00267a43, // n0x1e6d c0x0000 (---------------) + I int 0x00214d03, // n0x1e6e c0x0000 (---------------) + I mil 0x0021e283, // n0x1e6f c0x0000 (---------------) + I net 0x00223a43, // n0x1e70 c0x0000 (---------------) + I org 0x00226e03, // n0x1e71 c0x0000 (---------------) + I rec 0x003758c5, // n0x1e72 c0x0000 (---------------) + I store 0x0023da03, // n0x1e73 c0x0000 (---------------) + I tec 0x002292c3, // n0x1e74 c0x0000 (---------------) + I web 0x00203dc2, // n0x1e75 c0x0000 (---------------) + I co 0x0022d0c3, // n0x1e76 c0x0000 (---------------) + I com 0x00369643, // n0x1e77 c0x0000 (---------------) + I k12 0x0021e283, // n0x1e78 c0x0000 (---------------) + I net 0x00223a43, // n0x1e79 c0x0000 (---------------) + I org 0x00203982, // n0x1e7a c0x0000 (---------------) + I ac 0x00325b83, // n0x1e7b c0x0000 (---------------) + I biz 0x000f4e08, // n0x1e7c c0x0000 (---------------) + blogspot 0x0022d0c3, // n0x1e7d c0x0000 (---------------) + I com 0x002325c3, // n0x1e7e c0x0000 (---------------) + I edu 0x00264783, // n0x1e7f c0x0000 (---------------) + I gov 0x00366f06, // n0x1e80 c0x0000 (---------------) + I health 0x003a4f84, // n0x1e81 c0x0000 (---------------) + I info 0x00267a43, // n0x1e82 c0x0000 (---------------) + I int 0x0020ff84, // n0x1e83 c0x0000 (---------------) + I name 0x0021e283, // n0x1e84 c0x0000 (---------------) + I net 0x00223a43, // n0x1e85 c0x0000 (---------------) + I org 0x00220443, // n0x1e86 c0x0000 (---------------) + I pro 0x0022d0c3, // n0x1e87 c0x0000 (---------------) + I com 0x002325c3, // n0x1e88 c0x0000 (---------------) + I edu 0x0021e283, // n0x1e89 c0x0000 (---------------) + I net 0x00223a43, // n0x1e8a c0x0000 (---------------) + I org 0x0022d0c3, // n0x1e8b c0x0000 (---------------) + I com 0x00020b06, // n0x1e8c c0x0000 (---------------) + dyndns 0x002325c3, // n0x1e8d c0x0000 (---------------) + I edu 0x00264783, // n0x1e8e c0x0000 (---------------) + I gov 0x000cab86, // n0x1e8f c0x0000 (---------------) + mypets 0x0021e283, // n0x1e90 c0x0000 (---------------) + I net 0x00223a43, // n0x1e91 c0x0000 (---------------) + I org 0x00300988, // n0x1e92 c0x0000 (---------------) + I xn--80au 0x00305949, // n0x1e93 c0x0000 (---------------) + I xn--90azh 0x003121c9, // n0x1e94 c0x0000 (---------------) + I xn--c1avg 0x0031f608, // n0x1e95 c0x0000 (---------------) + I xn--d1at 0x0036ee08, // n0x1e96 c0x0000 (---------------) + I xn--o1ac 0x0036ee09, // n0x1e97 c0x0000 (---------------) + I xn--o1ach 0x00203982, // n0x1e98 c0x0000 (---------------) + I ac 0x002ffac6, // n0x1e99 c0x0000 (---------------) + I agrica 0x00200d43, // n0x1e9a c0x0000 (---------------) + I alt 0x65603dc2, // n0x1e9b c0x0195 (n0x1ea9-n0x1eaa) + I co 0x002325c3, // n0x1e9c c0x0000 (---------------) + I edu 0x00264783, // n0x1e9d c0x0000 (---------------) + I gov 0x0025e007, // n0x1e9e c0x0000 (---------------) + I grondar 0x00266983, // n0x1e9f c0x0000 (---------------) + I law 0x00214d03, // n0x1ea0 c0x0000 (---------------) + I mil 0x0021e283, // n0x1ea1 c0x0000 (---------------) + I net 0x002006c3, // n0x1ea2 c0x0000 (---------------) + I ngo 0x00211503, // n0x1ea3 c0x0000 (---------------) + I nis 0x0020f543, // n0x1ea4 c0x0000 (---------------) + I nom 0x00223a43, // n0x1ea5 c0x0000 (---------------) + I org 0x00381f46, // n0x1ea6 c0x0000 (---------------) + I school 0x00200142, // n0x1ea7 c0x0000 (---------------) + I tm 0x002292c3, // n0x1ea8 c0x0000 (---------------) + I web 0x000f4e08, // n0x1ea9 c0x0000 (---------------) + blogspot } // children is the list of nodes' children, the parent's wildcard bit and the // parent's node type. If a node has no children then their children index // will be in the range [0, 6), depending on the wildcard bit and node type. // // The layout within the uint32, from MSB to LSB, is: // [ 1 bits] unused // [ 1 bits] wildcard bit // [ 2 bits] node type // [14 bits] high nodes index (exclusive) of children // [14 bits] low nodes index (inclusive) of children var children = [...]uint32{ 0x00000000, // c0x0000 (---------------) + 0x10000000, // c0x0001 (---------------) ! 0x20000000, // c0x0002 (---------------) o 0x40000000, // c0x0003 (---------------)* + 0x50000000, // c0x0004 (---------------)* ! 0x60000000, // c0x0005 (---------------)* o 0x018105fe, // c0x0006 (n0x05fe-n0x0604) + 0x01814604, // c0x0007 (n0x0604-n0x0605) + 0x01834605, // c0x0008 (n0x0605-n0x060d) + 0x0199060d, // c0x0009 (n0x060d-n0x0664) + 0x019a4664, // c0x000a (n0x0664-n0x0669) + 0x019b8669, // c0x000b (n0x0669-n0x066e) + 0x019c866e, // c0x000c (n0x066e-n0x0672) + 0x019e4672, // c0x000d (n0x0672-n0x0679) + 0x019e8679, // c0x000e (n0x0679-n0x067a) + 0x01a0067a, // c0x000f (n0x067a-n0x0680) + 0x01a24680, // c0x0010 (n0x0680-n0x0689) + 0x01a28689, // c0x0011 (n0x0689-n0x068a) + 0x01a4068a, // c0x0012 (n0x068a-n0x0690) + 0x01a44690, // c0x0013 (n0x0690-n0x0691) + 0x01a60691, // c0x0014 (n0x0691-n0x0698) + 0x01a64698, // c0x0015 (n0x0698-n0x0699) + 0x01aac699, // c0x0016 (n0x0699-n0x06ab) + 0x01ab06ab, // c0x0017 (n0x06ab-n0x06ac) + 0x01ad06ac, // c0x0018 (n0x06ac-n0x06b4) + 0x01ae46b4, // c0x0019 (n0x06b4-n0x06b9) + 0x01ae86b9, // c0x001a (n0x06b9-n0x06ba) + 0x01b186ba, // c0x001b (n0x06ba-n0x06c6) + 0x01b446c6, // c0x001c (n0x06c6-n0x06d1) + 0x01b6c6d1, // c0x001d (n0x06d1-n0x06db) + 0x01b746db, // c0x001e (n0x06db-n0x06dd) + 0x01b786dd, // c0x001f (n0x06dd-n0x06de) + 0x01c0c6de, // c0x0020 (n0x06de-n0x0703) + 0x01c20703, // c0x0021 (n0x0703-n0x0708) + 0x01c34708, // c0x0022 (n0x0708-n0x070d) + 0x01c5470d, // c0x0023 (n0x070d-n0x0715) + 0x01c64715, // c0x0024 (n0x0715-n0x0719) + 0x01c78719, // c0x0025 (n0x0719-n0x071e) + 0x01c9c71e, // c0x0026 (n0x071e-n0x0727) + 0x01db4727, // c0x0027 (n0x0727-n0x076d) + 0x01db876d, // c0x0028 (n0x076d-n0x076e) + 0x01dcc76e, // c0x0029 (n0x076e-n0x0773) + 0x01de0773, // c0x002a (n0x0773-n0x0778) + 0x01de8778, // c0x002b (n0x0778-n0x077a) + 0x01df877a, // c0x002c (n0x077a-n0x077e) + 0x01dfc77e, // c0x002d (n0x077e-n0x077f) + 0x01e1477f, // c0x002e (n0x077f-n0x0785) + 0x01e58785, // c0x002f (n0x0785-n0x0796) + 0x01e68796, // c0x0030 (n0x0796-n0x079a) + 0x01e6c79a, // c0x0031 (n0x079a-n0x079b) + 0x01e7079b, // c0x0032 (n0x079b-n0x079c) + 0x01e7479c, // c0x0033 (n0x079c-n0x079d) + 0x01eb079d, // c0x0034 (n0x079d-n0x07ac) + 0x61eb47ac, // c0x0035 (n0x07ac-n0x07ad)* o 0x01ec87ad, // c0x0036 (n0x07ad-n0x07b2) + 0x01ed87b2, // c0x0037 (n0x07b2-n0x07b6) + 0x01f8c7b6, // c0x0038 (n0x07b6-n0x07e3) + 0x21f907e3, // c0x0039 (n0x07e3-n0x07e4) o 0x01f947e4, // c0x003a (n0x07e4-n0x07e5) + 0x01f987e5, // c0x003b (n0x07e5-n0x07e6) + 0x21f9c7e6, // c0x003c (n0x07e6-n0x07e7) o 0x21fa07e7, // c0x003d (n0x07e7-n0x07e8) o 0x01fd47e8, // c0x003e (n0x07e8-n0x07f5) + 0x01fd87f5, // c0x003f (n0x07f5-n0x07f6) + 0x023187f6, // c0x0040 (n0x07f6-n0x08c6) + 0x223608c6, // c0x0041 (n0x08c6-n0x08d8) o 0x023848d8, // c0x0042 (n0x08d8-n0x08e1) + 0x0238c8e1, // c0x0043 (n0x08e1-n0x08e3) + 0x223908e3, // c0x0044 (n0x08e3-n0x08e4) o 0x023ac8e4, // c0x0045 (n0x08e4-n0x08eb) + 0x023c48eb, // c0x0046 (n0x08eb-n0x08f1) + 0x023c88f1, // c0x0047 (n0x08f1-n0x08f2) + 0x023d88f2, // c0x0048 (n0x08f2-n0x08f6) + 0x023e08f6, // c0x0049 (n0x08f6-n0x08f8) + 0x224148f8, // c0x004a (n0x08f8-n0x0905) o 0x02418905, // c0x004b (n0x0905-n0x0906) + 0x0241c906, // c0x004c (n0x0906-n0x0907) + 0x0243c907, // c0x004d (n0x0907-n0x090f) + 0x0244090f, // c0x004e (n0x090f-n0x0910) + 0x02454910, // c0x004f (n0x0910-n0x0915) + 0x0247c915, // c0x0050 (n0x0915-n0x091f) + 0x0249c91f, // c0x0051 (n0x091f-n0x0927) + 0x024cc927, // c0x0052 (n0x0927-n0x0933) + 0x024f4933, // c0x0053 (n0x0933-n0x093d) + 0x024f893d, // c0x0054 (n0x093d-n0x093e) + 0x0251c93e, // c0x0055 (n0x093e-n0x0947) + 0x02520947, // c0x0056 (n0x0947-n0x0948) + 0x02534948, // c0x0057 (n0x0948-n0x094d) + 0x0253894d, // c0x0058 (n0x094d-n0x094e) + 0x0255894e, // c0x0059 (n0x094e-n0x0956) + 0x02564956, // c0x005a (n0x0956-n0x0959) + 0x025c4959, // c0x005b (n0x0959-n0x0971) + 0x025e0971, // c0x005c (n0x0971-n0x0978) + 0x025ec978, // c0x005d (n0x0978-n0x097b) + 0x0260097b, // c0x005e (n0x097b-n0x0980) + 0x02618980, // c0x005f (n0x0980-n0x0986) + 0x0262c986, // c0x0060 (n0x0986-n0x098b) + 0x0264498b, // c0x0061 (n0x098b-n0x0991) + 0x0265c991, // c0x0062 (n0x0991-n0x0997) + 0x02674997, // c0x0063 (n0x0997-n0x099d) + 0x0269099d, // c0x0064 (n0x099d-n0x09a4) + 0x0269c9a4, // c0x0065 (n0x09a4-n0x09a7) + 0x026fc9a7, // c0x0066 (n0x09a7-n0x09bf) + 0x027149bf, // c0x0067 (n0x09bf-n0x09c5) + 0x027289c5, // c0x0068 (n0x09c5-n0x09ca) + 0x0276c9ca, // c0x0069 (n0x09ca-n0x09db) + 0x027ec9db, // c0x006a (n0x09db-n0x09fb) + 0x028189fb, // c0x006b (n0x09fb-n0x0a06) + 0x0281ca06, // c0x006c (n0x0a06-n0x0a07) + 0x02824a07, // c0x006d (n0x0a07-n0x0a09) + 0x02844a09, // c0x006e (n0x0a09-n0x0a11) + 0x02848a11, // c0x006f (n0x0a11-n0x0a12) + 0x02864a12, // c0x0070 (n0x0a12-n0x0a19) + 0x0286ca19, // c0x0071 (n0x0a19-n0x0a1b) + 0x028a0a1b, // c0x0072 (n0x0a1b-n0x0a28) + 0x028c8a28, // c0x0073 (n0x0a28-n0x0a32) + 0x028cca32, // c0x0074 (n0x0a32-n0x0a33) + 0x028e4a33, // c0x0075 (n0x0a33-n0x0a39) + 0x028fca39, // c0x0076 (n0x0a39-n0x0a3f) + 0x02920a3f, // c0x0077 (n0x0a3f-n0x0a48) + 0x02940a48, // c0x0078 (n0x0a48-n0x0a50) + 0x02f04a50, // c0x0079 (n0x0a50-n0x0bc1) + 0x02f10bc1, // c0x007a (n0x0bc1-n0x0bc4) + 0x02f30bc4, // c0x007b (n0x0bc4-n0x0bcc) + 0x030ecbcc, // c0x007c (n0x0bcc-n0x0c3b) + 0x031bcc3b, // c0x007d (n0x0c3b-n0x0c6f) + 0x0322cc6f, // c0x007e (n0x0c6f-n0x0c8b) + 0x03284c8b, // c0x007f (n0x0c8b-n0x0ca1) + 0x0336cca1, // c0x0080 (n0x0ca1-n0x0cdb) + 0x033c4cdb, // c0x0081 (n0x0cdb-n0x0cf1) + 0x03400cf1, // c0x0082 (n0x0cf1-n0x0d00) + 0x034fcd00, // c0x0083 (n0x0d00-n0x0d3f) + 0x035c8d3f, // c0x0084 (n0x0d3f-n0x0d72) + 0x03660d72, // c0x0085 (n0x0d72-n0x0d98) + 0x036f0d98, // c0x0086 (n0x0d98-n0x0dbc) + 0x03754dbc, // c0x0087 (n0x0dbc-n0x0dd5) + 0x0398cdd5, // c0x0088 (n0x0dd5-n0x0e63) + 0x03a44e63, // c0x0089 (n0x0e63-n0x0e91) + 0x03b10e91, // c0x008a (n0x0e91-n0x0ec4) + 0x03b5cec4, // c0x008b (n0x0ec4-n0x0ed7) + 0x03be4ed7, // c0x008c (n0x0ed7-n0x0ef9) + 0x03c20ef9, // c0x008d (n0x0ef9-n0x0f08) + 0x03c70f08, // c0x008e (n0x0f08-n0x0f1c) + 0x03ce8f1c, // c0x008f (n0x0f1c-n0x0f3a) + 0x63cecf3a, // c0x0090 (n0x0f3a-n0x0f3b)* o 0x63cf0f3b, // c0x0091 (n0x0f3b-n0x0f3c)* o 0x63cf4f3c, // c0x0092 (n0x0f3c-n0x0f3d)* o 0x03d70f3d, // c0x0093 (n0x0f3d-n0x0f5c) + 0x03dd8f5c, // c0x0094 (n0x0f5c-n0x0f76) + 0x03e54f76, // c0x0095 (n0x0f76-n0x0f95) + 0x03eccf95, // c0x0096 (n0x0f95-n0x0fb3) + 0x03f50fb3, // c0x0097 (n0x0fb3-n0x0fd4) + 0x03fbcfd4, // c0x0098 (n0x0fd4-n0x0fef) + 0x040e8fef, // c0x0099 (n0x0fef-n0x103a) + 0x0414103a, // c0x009a (n0x103a-n0x1050) + 0x64145050, // c0x009b (n0x1050-n0x1051)* o 0x041dd051, // c0x009c (n0x1051-n0x1077) + 0x04265077, // c0x009d (n0x1077-n0x1099) + 0x042b1099, // c0x009e (n0x1099-n0x10ac) + 0x043190ac, // c0x009f (n0x10ac-n0x10c6) + 0x043c10c6, // c0x00a0 (n0x10c6-n0x10f0) + 0x044890f0, // c0x00a1 (n0x10f0-n0x1122) + 0x044f1122, // c0x00a2 (n0x1122-n0x113c) + 0x0460513c, // c0x00a3 (n0x113c-n0x1181) + 0x64609181, // c0x00a4 (n0x1181-n0x1182)* o 0x6460d182, // c0x00a5 (n0x1182-n0x1183)* o 0x04669183, // c0x00a6 (n0x1183-n0x119a) + 0x046c519a, // c0x00a7 (n0x119a-n0x11b1) + 0x047551b1, // c0x00a8 (n0x11b1-n0x11d5) + 0x047d11d5, // c0x00a9 (n0x11d5-n0x11f4) + 0x048151f4, // c0x00aa (n0x11f4-n0x1205) + 0x048f9205, // c0x00ab (n0x1205-n0x123e) + 0x0492d23e, // c0x00ac (n0x123e-n0x124b) + 0x0498d24b, // c0x00ad (n0x124b-n0x1263) + 0x04a01263, // c0x00ae (n0x1263-n0x1280) + 0x04a89280, // c0x00af (n0x1280-n0x12a2) + 0x04ac92a2, // c0x00b0 (n0x12a2-n0x12b2) + 0x04b392b2, // c0x00b1 (n0x12b2-n0x12ce) + 0x64b3d2ce, // c0x00b2 (n0x12ce-n0x12cf)* o 0x64b412cf, // c0x00b3 (n0x12cf-n0x12d0)* o 0x24b452d0, // c0x00b4 (n0x12d0-n0x12d1) o 0x04b5d2d1, // c0x00b5 (n0x12d1-n0x12d7) + 0x04b792d7, // c0x00b6 (n0x12d7-n0x12de) + 0x04bbd2de, // c0x00b7 (n0x12de-n0x12ef) + 0x04bcd2ef, // c0x00b8 (n0x12ef-n0x12f3) + 0x04be52f3, // c0x00b9 (n0x12f3-n0x12f9) + 0x04c5d2f9, // c0x00ba (n0x12f9-n0x1317) + 0x04c71317, // c0x00bb (n0x1317-n0x131c) + 0x04c8931c, // c0x00bc (n0x131c-n0x1322) + 0x04cad322, // c0x00bd (n0x1322-n0x132b) + 0x04cc132b, // c0x00be (n0x132b-n0x1330) + 0x04cd9330, // c0x00bf (n0x1330-n0x1336) + 0x04cdd336, // c0x00c0 (n0x1336-n0x1337) + 0x04d19337, // c0x00c1 (n0x1337-n0x1346) + 0x04d2d346, // c0x00c2 (n0x1346-n0x134b) + 0x04d3534b, // c0x00c3 (n0x134b-n0x134d) + 0x04d3d34d, // c0x00c4 (n0x134d-n0x134f) + 0x04d4134f, // c0x00c5 (n0x134f-n0x1350) + 0x04d65350, // c0x00c6 (n0x1350-n0x1359) + 0x04d89359, // c0x00c7 (n0x1359-n0x1362) + 0x04da1362, // c0x00c8 (n0x1362-n0x1368) + 0x04da9368, // c0x00c9 (n0x1368-n0x136a) + 0x04dad36a, // c0x00ca (n0x136a-n0x136b) + 0x04de136b, // c0x00cb (n0x136b-n0x1378) + 0x04e05378, // c0x00cc (n0x1378-n0x1381) + 0x04e25381, // c0x00cd (n0x1381-n0x1389) + 0x04e41389, // c0x00ce (n0x1389-n0x1390) + 0x04e51390, // c0x00cf (n0x1390-n0x1394) + 0x04e65394, // c0x00d0 (n0x1394-n0x1399) + 0x04e69399, // c0x00d1 (n0x1399-n0x139a) + 0x04e7139a, // c0x00d2 (n0x139a-n0x139c) + 0x04e8539c, // c0x00d3 (n0x139c-n0x13a1) + 0x04e953a1, // c0x00d4 (n0x13a1-n0x13a5) + 0x04e993a5, // c0x00d5 (n0x13a5-n0x13a6) + 0x04eb53a6, // c0x00d6 (n0x13a6-n0x13ad) + 0x057453ad, // c0x00d7 (n0x13ad-n0x15d1) + 0x0577d5d1, // c0x00d8 (n0x15d1-n0x15df) + 0x057a95df, // c0x00d9 (n0x15df-n0x15ea) + 0x057c15ea, // c0x00da (n0x15ea-n0x15f0) + 0x057e15f0, // c0x00db (n0x15f0-n0x15f8) + 0x657e55f8, // c0x00dc (n0x15f8-n0x15f9)* o 0x058295f9, // c0x00dd (n0x15f9-n0x160a) + 0x0583160a, // c0x00de (n0x160a-n0x160c) + 0x2583560c, // c0x00df (n0x160c-n0x160d) o 0x2583960d, // c0x00e0 (n0x160d-n0x160e) o 0x0583d60e, // c0x00e1 (n0x160e-n0x160f) + 0x0590d60f, // c0x00e2 (n0x160f-n0x1643) + 0x25911643, // c0x00e3 (n0x1643-n0x1644) o 0x25919644, // c0x00e4 (n0x1644-n0x1646) o 0x25921646, // c0x00e5 (n0x1646-n0x1648) o 0x2592d648, // c0x00e6 (n0x1648-n0x164b) o 0x0595564b, // c0x00e7 (n0x164b-n0x1655) + 0x05979655, // c0x00e8 (n0x1655-n0x165e) + 0x0597d65e, // c0x00e9 (n0x165e-n0x165f) + 0x259b565f, // c0x00ea (n0x165f-n0x166d) o 0x059c166d, // c0x00eb (n0x166d-n0x1670) + 0x06519670, // c0x00ec (n0x1670-n0x1946) + 0x0651d946, // c0x00ed (n0x1946-n0x1947) + 0x06521947, // c0x00ee (n0x1947-n0x1948) + 0x26525948, // c0x00ef (n0x1948-n0x1949) o 0x06529949, // c0x00f0 (n0x1949-n0x194a) + 0x2652d94a, // c0x00f1 (n0x194a-n0x194b) o 0x0653194b, // c0x00f2 (n0x194b-n0x194c) + 0x2653d94c, // c0x00f3 (n0x194c-n0x194f) o 0x0654194f, // c0x00f4 (n0x194f-n0x1950) + 0x06545950, // c0x00f5 (n0x1950-n0x1951) + 0x26549951, // c0x00f6 (n0x1951-n0x1952) o 0x0654d952, // c0x00f7 (n0x1952-n0x1953) + 0x26555953, // c0x00f8 (n0x1953-n0x1955) o 0x06559955, // c0x00f9 (n0x1955-n0x1956) + 0x0655d956, // c0x00fa (n0x1956-n0x1957) + 0x2656d957, // c0x00fb (n0x1957-n0x195b) o 0x0657195b, // c0x00fc (n0x195b-n0x195c) + 0x0657595c, // c0x00fd (n0x195c-n0x195d) + 0x0657995d, // c0x00fe (n0x195d-n0x195e) + 0x0657d95e, // c0x00ff (n0x195e-n0x195f) + 0x2658195f, // c0x0100 (n0x195f-n0x1960) o 0x06585960, // c0x0101 (n0x1960-n0x1961) + 0x06589961, // c0x0102 (n0x1961-n0x1962) + 0x0658d962, // c0x0103 (n0x1962-n0x1963) + 0x06591963, // c0x0104 (n0x1963-n0x1964) + 0x26599964, // c0x0105 (n0x1964-n0x1966) o 0x0659d966, // c0x0106 (n0x1966-n0x1967) + 0x065a1967, // c0x0107 (n0x1967-n0x1968) + 0x065a5968, // c0x0108 (n0x1968-n0x1969) + 0x265a9969, // c0x0109 (n0x1969-n0x196a) o 0x065ad96a, // c0x010a (n0x196a-n0x196b) + 0x265b596b, // c0x010b (n0x196b-n0x196d) o 0x265b996d, // c0x010c (n0x196d-n0x196e) o 0x065d596e, // c0x010d (n0x196e-n0x1975) + 0x065e1975, // c0x010e (n0x1975-n0x1978) + 0x06621978, // c0x010f (n0x1978-n0x1988) + 0x06625988, // c0x0110 (n0x1988-n0x1989) + 0x06649989, // c0x0111 (n0x1989-n0x1992) + 0x0673d992, // c0x0112 (n0x1992-n0x19cf) + 0x267459cf, // c0x0113 (n0x19cf-n0x19d1) o 0x267499d1, // c0x0114 (n0x19d1-n0x19d2) o 0x2674d9d2, // c0x0115 (n0x19d2-n0x19d3) o 0x067559d3, // c0x0116 (n0x19d3-n0x19d5) + 0x068319d5, // c0x0117 (n0x19d5-n0x1a0c) + 0x0685da0c, // c0x0118 (n0x1a0c-n0x1a17) + 0x0687da17, // c0x0119 (n0x1a17-n0x1a1f) + 0x06889a1f, // c0x011a (n0x1a1f-n0x1a22) + 0x068a9a22, // c0x011b (n0x1a22-n0x1a2a) + 0x068e1a2a, // c0x011c (n0x1a2a-n0x1a38) + 0x06b75a38, // c0x011d (n0x1a38-n0x1add) + 0x06c31add, // c0x011e (n0x1add-n0x1b0c) + 0x06c45b0c, // c0x011f (n0x1b0c-n0x1b11) + 0x06c79b11, // c0x0120 (n0x1b11-n0x1b1e) + 0x06c95b1e, // c0x0121 (n0x1b1e-n0x1b25) + 0x06cb1b25, // c0x0122 (n0x1b25-n0x1b2c) + 0x06cd5b2c, // c0x0123 (n0x1b2c-n0x1b35) + 0x06cedb35, // c0x0124 (n0x1b35-n0x1b3b) + 0x06d09b3b, // c0x0125 (n0x1b3b-n0x1b42) + 0x06d2db42, // c0x0126 (n0x1b42-n0x1b4b) + 0x06d3db4b, // c0x0127 (n0x1b4b-n0x1b4f) + 0x06d6db4f, // c0x0128 (n0x1b4f-n0x1b5b) + 0x06d89b5b, // c0x0129 (n0x1b5b-n0x1b62) + 0x06f95b62, // c0x012a (n0x1b62-n0x1be5) + 0x06fb9be5, // c0x012b (n0x1be5-n0x1bee) + 0x06fd9bee, // c0x012c (n0x1bee-n0x1bf6) + 0x06fedbf6, // c0x012d (n0x1bf6-n0x1bfb) + 0x07001bfb, // c0x012e (n0x1bfb-n0x1c00) + 0x07021c00, // c0x012f (n0x1c00-n0x1c08) + 0x070c5c08, // c0x0130 (n0x1c08-n0x1c31) + 0x070e1c31, // c0x0131 (n0x1c31-n0x1c38) + 0x070fdc38, // c0x0132 (n0x1c38-n0x1c3f) + 0x07101c3f, // c0x0133 (n0x1c3f-n0x1c40) + 0x07105c40, // c0x0134 (n0x1c40-n0x1c41) + 0x07119c41, // c0x0135 (n0x1c41-n0x1c46) + 0x07139c46, // c0x0136 (n0x1c46-n0x1c4e) + 0x07145c4e, // c0x0137 (n0x1c4e-n0x1c51) + 0x07175c51, // c0x0138 (n0x1c51-n0x1c5d) + 0x071f5c5d, // c0x0139 (n0x1c5d-n0x1c7d) + 0x07209c7d, // c0x013a (n0x1c7d-n0x1c82) + 0x0720dc82, // c0x013b (n0x1c82-n0x1c83) + 0x07225c83, // c0x013c (n0x1c83-n0x1c89) + 0x07231c89, // c0x013d (n0x1c89-n0x1c8c) + 0x07235c8c, // c0x013e (n0x1c8c-n0x1c8d) + 0x07251c8d, // c0x013f (n0x1c8d-n0x1c94) + 0x0728dc94, // c0x0140 (n0x1c94-n0x1ca3) + 0x07291ca3, // c0x0141 (n0x1ca3-n0x1ca4) + 0x072b1ca4, // c0x0142 (n0x1ca4-n0x1cac) + 0x07301cac, // c0x0143 (n0x1cac-n0x1cc0) + 0x07319cc0, // c0x0144 (n0x1cc0-n0x1cc6) + 0x0736dcc6, // c0x0145 (n0x1cc6-n0x1cdb) + 0x07371cdb, // c0x0146 (n0x1cdb-n0x1cdc) + 0x07375cdc, // c0x0147 (n0x1cdc-n0x1cdd) + 0x073b9cdd, // c0x0148 (n0x1cdd-n0x1cee) + 0x073c9cee, // c0x0149 (n0x1cee-n0x1cf2) + 0x07401cf2, // c0x014a (n0x1cf2-n0x1d00) + 0x07431d00, // c0x014b (n0x1d00-n0x1d0c) + 0x0756dd0c, // c0x014c (n0x1d0c-n0x1d5b) + 0x07591d5b, // c0x014d (n0x1d5b-n0x1d64) + 0x075bdd64, // c0x014e (n0x1d64-n0x1d6f) + 0x075c1d6f, // c0x014f (n0x1d6f-n0x1d70) + 0x075c5d70, // c0x0150 (n0x1d70-n0x1d71) + 0x076c1d71, // c0x0151 (n0x1d71-n0x1db0) + 0x076cddb0, // c0x0152 (n0x1db0-n0x1db3) + 0x076d9db3, // c0x0153 (n0x1db3-n0x1db6) + 0x076e5db6, // c0x0154 (n0x1db6-n0x1db9) + 0x076f1db9, // c0x0155 (n0x1db9-n0x1dbc) + 0x076fddbc, // c0x0156 (n0x1dbc-n0x1dbf) + 0x07709dbf, // c0x0157 (n0x1dbf-n0x1dc2) + 0x07715dc2, // c0x0158 (n0x1dc2-n0x1dc5) + 0x07721dc5, // c0x0159 (n0x1dc5-n0x1dc8) + 0x0772ddc8, // c0x015a (n0x1dc8-n0x1dcb) + 0x07739dcb, // c0x015b (n0x1dcb-n0x1dce) + 0x07745dce, // c0x015c (n0x1dce-n0x1dd1) + 0x07751dd1, // c0x015d (n0x1dd1-n0x1dd4) + 0x0775ddd4, // c0x015e (n0x1dd4-n0x1dd7) + 0x07765dd7, // c0x015f (n0x1dd7-n0x1dd9) + 0x07771dd9, // c0x0160 (n0x1dd9-n0x1ddc) + 0x0777dddc, // c0x0161 (n0x1ddc-n0x1ddf) + 0x07789ddf, // c0x0162 (n0x1ddf-n0x1de2) + 0x07795de2, // c0x0163 (n0x1de2-n0x1de5) + 0x077a1de5, // c0x0164 (n0x1de5-n0x1de8) + 0x077adde8, // c0x0165 (n0x1de8-n0x1deb) + 0x077b9deb, // c0x0166 (n0x1deb-n0x1dee) + 0x077c5dee, // c0x0167 (n0x1dee-n0x1df1) + 0x077d1df1, // c0x0168 (n0x1df1-n0x1df4) + 0x077dddf4, // c0x0169 (n0x1df4-n0x1df7) + 0x077e9df7, // c0x016a (n0x1df7-n0x1dfa) + 0x077f5dfa, // c0x016b (n0x1dfa-n0x1dfd) + 0x07801dfd, // c0x016c (n0x1dfd-n0x1e00) + 0x0780de00, // c0x016d (n0x1e00-n0x1e03) + 0x07819e03, // c0x016e (n0x1e03-n0x1e06) + 0x07825e06, // c0x016f (n0x1e06-n0x1e09) + 0x07831e09, // c0x0170 (n0x1e09-n0x1e0c) + 0x07839e0c, // c0x0171 (n0x1e0c-n0x1e0e) + 0x07845e0e, // c0x0172 (n0x1e0e-n0x1e11) + 0x07851e11, // c0x0173 (n0x1e11-n0x1e14) + 0x0785de14, // c0x0174 (n0x1e14-n0x1e17) + 0x07869e17, // c0x0175 (n0x1e17-n0x1e1a) + 0x07875e1a, // c0x0176 (n0x1e1a-n0x1e1d) + 0x07881e1d, // c0x0177 (n0x1e1d-n0x1e20) + 0x0788de20, // c0x0178 (n0x1e20-n0x1e23) + 0x07899e23, // c0x0179 (n0x1e23-n0x1e26) + 0x078a5e26, // c0x017a (n0x1e26-n0x1e29) + 0x078b1e29, // c0x017b (n0x1e29-n0x1e2c) + 0x078bde2c, // c0x017c (n0x1e2c-n0x1e2f) + 0x078c9e2f, // c0x017d (n0x1e2f-n0x1e32) + 0x078d5e32, // c0x017e (n0x1e32-n0x1e35) + 0x078dde35, // c0x017f (n0x1e35-n0x1e37) + 0x078e9e37, // c0x0180 (n0x1e37-n0x1e3a) + 0x078f5e3a, // c0x0181 (n0x1e3a-n0x1e3d) + 0x07901e3d, // c0x0182 (n0x1e3d-n0x1e40) + 0x0790de40, // c0x0183 (n0x1e40-n0x1e43) + 0x07919e43, // c0x0184 (n0x1e43-n0x1e46) + 0x07925e46, // c0x0185 (n0x1e46-n0x1e49) + 0x07931e49, // c0x0186 (n0x1e49-n0x1e4c) + 0x0793de4c, // c0x0187 (n0x1e4c-n0x1e4f) + 0x07941e4f, // c0x0188 (n0x1e4f-n0x1e50) + 0x0794de50, // c0x0189 (n0x1e50-n0x1e53) + 0x07965e53, // c0x018a (n0x1e53-n0x1e59) + 0x07969e59, // c0x018b (n0x1e59-n0x1e5a) + 0x07979e5a, // c0x018c (n0x1e5a-n0x1e5e) + 0x07991e5e, // c0x018d (n0x1e5e-n0x1e64) + 0x079d5e64, // c0x018e (n0x1e64-n0x1e75) + 0x079e9e75, // c0x018f (n0x1e75-n0x1e7a) + 0x07a1de7a, // c0x0190 (n0x1e7a-n0x1e87) + 0x07a2de87, // c0x0191 (n0x1e87-n0x1e8b) + 0x07a49e8b, // c0x0192 (n0x1e8b-n0x1e92) + 0x07a61e92, // c0x0193 (n0x1e92-n0x1e98) + 0x27aa5e98, // c0x0194 (n0x1e98-n0x1ea9) o 0x07aa9ea9, // c0x0195 (n0x1ea9-n0x1eaa) + } // max children 405 (capacity 511) // max text offset 26956 (capacity 32767) // max text length 36 (capacity 63) // max hi 7850 (capacity 16383) // max lo 7849 (capacity 16383) golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/publicsuffix/table_test.go000066400000000000000000006343611264464372400256350ustar00rootroot00000000000000// generated by go run gen.go; DO NOT EDIT package publicsuffix var rules = [...]string{ "ac", "com.ac", "edu.ac", "gov.ac", "net.ac", "mil.ac", "org.ac", "ad", "nom.ad", "ae", "co.ae", "net.ae", "org.ae", "sch.ae", "ac.ae", "gov.ae", "mil.ae", "aero", "accident-investigation.aero", "accident-prevention.aero", "aerobatic.aero", "aeroclub.aero", "aerodrome.aero", "agents.aero", "aircraft.aero", "airline.aero", "airport.aero", "air-surveillance.aero", "airtraffic.aero", "air-traffic-control.aero", "ambulance.aero", "amusement.aero", "association.aero", "author.aero", "ballooning.aero", "broker.aero", "caa.aero", "cargo.aero", "catering.aero", "certification.aero", "championship.aero", "charter.aero", "civilaviation.aero", "club.aero", "conference.aero", "consultant.aero", "consulting.aero", "control.aero", "council.aero", "crew.aero", "design.aero", "dgca.aero", "educator.aero", "emergency.aero", "engine.aero", "engineer.aero", "entertainment.aero", "equipment.aero", "exchange.aero", "express.aero", "federation.aero", "flight.aero", "freight.aero", "fuel.aero", "gliding.aero", "government.aero", "groundhandling.aero", "group.aero", "hanggliding.aero", "homebuilt.aero", "insurance.aero", "journal.aero", "journalist.aero", "leasing.aero", "logistics.aero", "magazine.aero", "maintenance.aero", "media.aero", "microlight.aero", "modelling.aero", "navigation.aero", "parachuting.aero", "paragliding.aero", "passenger-association.aero", "pilot.aero", "press.aero", "production.aero", "recreation.aero", "repbody.aero", "res.aero", "research.aero", "rotorcraft.aero", "safety.aero", "scientist.aero", "services.aero", "show.aero", "skydiving.aero", "software.aero", "student.aero", "trader.aero", "trading.aero", "trainer.aero", "union.aero", "workinggroup.aero", "works.aero", "af", "gov.af", "com.af", "org.af", "net.af", "edu.af", "ag", "com.ag", "org.ag", "net.ag", "co.ag", "nom.ag", "ai", "off.ai", "com.ai", "net.ai", "org.ai", "al", "com.al", "edu.al", "gov.al", "mil.al", "net.al", "org.al", "am", "ao", "ed.ao", "gv.ao", "og.ao", "co.ao", "pb.ao", "it.ao", "aq", "ar", "com.ar", "edu.ar", "gob.ar", "gov.ar", "int.ar", "mil.ar", "net.ar", "org.ar", "tur.ar", "arpa", "e164.arpa", "in-addr.arpa", "ip6.arpa", "iris.arpa", "uri.arpa", "urn.arpa", "as", "gov.as", "asia", "at", "ac.at", "co.at", "gv.at", "or.at", "au", "com.au", "net.au", "org.au", "edu.au", "gov.au", "asn.au", "id.au", "info.au", "conf.au", "oz.au", "act.au", "nsw.au", "nt.au", "qld.au", "sa.au", "tas.au", "vic.au", "wa.au", "act.edu.au", "nsw.edu.au", "nt.edu.au", "qld.edu.au", "sa.edu.au", "tas.edu.au", "vic.edu.au", "wa.edu.au", "qld.gov.au", "sa.gov.au", "tas.gov.au", "vic.gov.au", "wa.gov.au", "aw", "com.aw", "ax", "az", "com.az", "net.az", "int.az", "gov.az", "org.az", "edu.az", "info.az", "pp.az", "mil.az", "name.az", "pro.az", "biz.az", "ba", "org.ba", "net.ba", "edu.ba", "gov.ba", "mil.ba", "unsa.ba", "unbi.ba", "co.ba", "com.ba", "rs.ba", "bb", "biz.bb", "co.bb", "com.bb", "edu.bb", "gov.bb", "info.bb", "net.bb", "org.bb", "store.bb", "tv.bb", "*.bd", "be", "ac.be", "bf", "gov.bf", "bg", "a.bg", "b.bg", "c.bg", "d.bg", "e.bg", "f.bg", "g.bg", "h.bg", "i.bg", "j.bg", "k.bg", "l.bg", "m.bg", "n.bg", "o.bg", "p.bg", "q.bg", "r.bg", "s.bg", "t.bg", "u.bg", "v.bg", "w.bg", "x.bg", "y.bg", "z.bg", "0.bg", "1.bg", "2.bg", "3.bg", "4.bg", "5.bg", "6.bg", "7.bg", "8.bg", "9.bg", "bh", "com.bh", "edu.bh", "net.bh", "org.bh", "gov.bh", "bi", "co.bi", "com.bi", "edu.bi", "or.bi", "org.bi", "biz", "bj", "asso.bj", "barreau.bj", "gouv.bj", "bm", "com.bm", "edu.bm", "gov.bm", "net.bm", "org.bm", "*.bn", "bo", "com.bo", "edu.bo", "gov.bo", "gob.bo", "int.bo", "org.bo", "net.bo", "mil.bo", "tv.bo", "br", "adm.br", "adv.br", "agr.br", "am.br", "arq.br", "art.br", "ato.br", "b.br", "bio.br", "blog.br", "bmd.br", "cim.br", "cng.br", "cnt.br", "com.br", "coop.br", "ecn.br", "eco.br", "edu.br", "emp.br", "eng.br", "esp.br", "etc.br", "eti.br", "far.br", "flog.br", "fm.br", "fnd.br", "fot.br", "fst.br", "g12.br", "ggf.br", "gov.br", "imb.br", "ind.br", "inf.br", "jor.br", "jus.br", "leg.br", "lel.br", "mat.br", "med.br", "mil.br", "mp.br", "mus.br", "net.br", "*.nom.br", "not.br", "ntr.br", "odo.br", "org.br", "ppg.br", "pro.br", "psc.br", "psi.br", "qsl.br", "radio.br", "rec.br", "slg.br", "srv.br", "taxi.br", "teo.br", "tmp.br", "trd.br", "tur.br", "tv.br", "vet.br", "vlog.br", "wiki.br", "zlg.br", "bs", "com.bs", "net.bs", "org.bs", "edu.bs", "gov.bs", "bt", "com.bt", "edu.bt", "gov.bt", "net.bt", "org.bt", "bv", "bw", "co.bw", "org.bw", "by", "gov.by", "mil.by", "com.by", "of.by", "bz", "com.bz", "net.bz", "org.bz", "edu.bz", "gov.bz", "ca", "ab.ca", "bc.ca", "mb.ca", "nb.ca", "nf.ca", "nl.ca", "ns.ca", "nt.ca", "nu.ca", "on.ca", "pe.ca", "qc.ca", "sk.ca", "yk.ca", "gc.ca", "cat", "cc", "cd", "gov.cd", "cf", "cg", "ch", "ci", "org.ci", "or.ci", "com.ci", "co.ci", "edu.ci", "ed.ci", "ac.ci", "net.ci", "go.ci", "asso.ci", "xn--aroport-bya.ci", "int.ci", "presse.ci", "md.ci", "gouv.ci", "*.ck", "!www.ck", "cl", "gov.cl", "gob.cl", "co.cl", "mil.cl", "cm", "co.cm", "com.cm", "gov.cm", "net.cm", "cn", "ac.cn", "com.cn", "edu.cn", "gov.cn", "net.cn", "org.cn", "mil.cn", "xn--55qx5d.cn", "xn--io0a7i.cn", "xn--od0alg.cn", "ah.cn", "bj.cn", "cq.cn", "fj.cn", "gd.cn", "gs.cn", "gz.cn", "gx.cn", "ha.cn", "hb.cn", "he.cn", "hi.cn", "hl.cn", "hn.cn", "jl.cn", "js.cn", "jx.cn", "ln.cn", "nm.cn", "nx.cn", "qh.cn", "sc.cn", "sd.cn", "sh.cn", "sn.cn", "sx.cn", "tj.cn", "xj.cn", "xz.cn", "yn.cn", "zj.cn", "hk.cn", "mo.cn", "tw.cn", "co", "arts.co", "com.co", "edu.co", "firm.co", "gov.co", "info.co", "int.co", "mil.co", "net.co", "nom.co", "org.co", "rec.co", "web.co", "com", "coop", "cr", "ac.cr", "co.cr", "ed.cr", "fi.cr", "go.cr", "or.cr", "sa.cr", "cu", "com.cu", "edu.cu", "org.cu", "net.cu", "gov.cu", "inf.cu", "cv", "cw", "com.cw", "edu.cw", "net.cw", "org.cw", "cx", "gov.cx", "ac.cy", "biz.cy", "com.cy", "ekloges.cy", "gov.cy", "ltd.cy", "name.cy", "net.cy", "org.cy", "parliament.cy", "press.cy", "pro.cy", "tm.cy", "cz", "de", "dj", "dk", "dm", "com.dm", "net.dm", "org.dm", "edu.dm", "gov.dm", "do", "art.do", "com.do", "edu.do", "gob.do", "gov.do", "mil.do", "net.do", "org.do", "sld.do", "web.do", "dz", "com.dz", "org.dz", "net.dz", "gov.dz", "edu.dz", "asso.dz", "pol.dz", "art.dz", "ec", "com.ec", "info.ec", "net.ec", "fin.ec", "k12.ec", "med.ec", "pro.ec", "org.ec", "edu.ec", "gov.ec", "gob.ec", "mil.ec", "edu", "ee", "edu.ee", "gov.ee", "riik.ee", "lib.ee", "med.ee", "com.ee", "pri.ee", "aip.ee", "org.ee", "fie.ee", "eg", "com.eg", "edu.eg", "eun.eg", "gov.eg", "mil.eg", "name.eg", "net.eg", "org.eg", "sci.eg", "*.er", "es", "com.es", "nom.es", "org.es", "gob.es", "edu.es", "et", "com.et", "gov.et", "org.et", "edu.et", "biz.et", "name.et", "info.et", "net.et", "eu", "fi", "aland.fi", "*.fj", "*.fk", "fm", "fo", "fr", "com.fr", "asso.fr", "nom.fr", "prd.fr", "presse.fr", "tm.fr", "aeroport.fr", "assedic.fr", "avocat.fr", "avoues.fr", "cci.fr", "chambagri.fr", "chirurgiens-dentistes.fr", "experts-comptables.fr", "geometre-expert.fr", "gouv.fr", "greta.fr", "huissier-justice.fr", "medecin.fr", "notaires.fr", "pharmacien.fr", "port.fr", "veterinaire.fr", "ga", "gb", "gd", "ge", "com.ge", "edu.ge", "gov.ge", "org.ge", "mil.ge", "net.ge", "pvt.ge", "gf", "gg", "co.gg", "net.gg", "org.gg", "gh", "com.gh", "edu.gh", "gov.gh", "org.gh", "mil.gh", "gi", "com.gi", "ltd.gi", "gov.gi", "mod.gi", "edu.gi", "org.gi", "gl", "co.gl", "com.gl", "edu.gl", "net.gl", "org.gl", "gm", "gn", "ac.gn", "com.gn", "edu.gn", "gov.gn", "org.gn", "net.gn", "gov", "gp", "com.gp", "net.gp", "mobi.gp", "edu.gp", "org.gp", "asso.gp", "gq", "gr", "com.gr", "edu.gr", "net.gr", "org.gr", "gov.gr", "gs", "gt", "com.gt", "edu.gt", "gob.gt", "ind.gt", "mil.gt", "net.gt", "org.gt", "*.gu", "gw", "gy", "co.gy", "com.gy", "net.gy", "hk", "com.hk", "edu.hk", "gov.hk", "idv.hk", "net.hk", "org.hk", "xn--55qx5d.hk", "xn--wcvs22d.hk", "xn--lcvr32d.hk", "xn--mxtq1m.hk", "xn--gmqw5a.hk", "xn--ciqpn.hk", "xn--gmq050i.hk", "xn--zf0avx.hk", "xn--io0a7i.hk", "xn--mk0axi.hk", "xn--od0alg.hk", "xn--od0aq3b.hk", "xn--tn0ag.hk", "xn--uc0atv.hk", "xn--uc0ay4a.hk", "hm", "hn", "com.hn", "edu.hn", "org.hn", "net.hn", "mil.hn", "gob.hn", "hr", "iz.hr", "from.hr", "name.hr", "com.hr", "ht", "com.ht", "shop.ht", "firm.ht", "info.ht", "adult.ht", "net.ht", "pro.ht", "org.ht", "med.ht", "art.ht", "coop.ht", "pol.ht", "asso.ht", "edu.ht", "rel.ht", "gouv.ht", "perso.ht", "hu", "co.hu", "info.hu", "org.hu", "priv.hu", "sport.hu", "tm.hu", "2000.hu", "agrar.hu", "bolt.hu", "casino.hu", "city.hu", "erotica.hu", "erotika.hu", "film.hu", "forum.hu", "games.hu", "hotel.hu", "ingatlan.hu", "jogasz.hu", "konyvelo.hu", "lakas.hu", "media.hu", "news.hu", "reklam.hu", "sex.hu", "shop.hu", "suli.hu", "szex.hu", "tozsde.hu", "utazas.hu", "video.hu", "id", "ac.id", "biz.id", "co.id", "desa.id", "go.id", "mil.id", "my.id", "net.id", "or.id", "sch.id", "web.id", "ie", "gov.ie", "il", "ac.il", "co.il", "gov.il", "idf.il", "k12.il", "muni.il", "net.il", "org.il", "im", "ac.im", "co.im", "com.im", "ltd.co.im", "net.im", "org.im", "plc.co.im", "tt.im", "tv.im", "in", "co.in", "firm.in", "net.in", "org.in", "gen.in", "ind.in", "nic.in", "ac.in", "edu.in", "res.in", "gov.in", "mil.in", "info", "int", "eu.int", "io", "com.io", "iq", "gov.iq", "edu.iq", "mil.iq", "com.iq", "org.iq", "net.iq", "ir", "ac.ir", "co.ir", "gov.ir", "id.ir", "net.ir", "org.ir", "sch.ir", "xn--mgba3a4f16a.ir", "xn--mgba3a4fra.ir", "is", "net.is", "com.is", "edu.is", "gov.is", "org.is", "int.is", "it", "gov.it", "edu.it", "abr.it", "abruzzo.it", "aosta-valley.it", "aostavalley.it", "bas.it", "basilicata.it", "cal.it", "calabria.it", "cam.it", "campania.it", "emilia-romagna.it", "emiliaromagna.it", "emr.it", "friuli-v-giulia.it", "friuli-ve-giulia.it", "friuli-vegiulia.it", "friuli-venezia-giulia.it", "friuli-veneziagiulia.it", "friuli-vgiulia.it", "friuliv-giulia.it", "friulive-giulia.it", "friulivegiulia.it", "friulivenezia-giulia.it", "friuliveneziagiulia.it", "friulivgiulia.it", "fvg.it", "laz.it", "lazio.it", "lig.it", "liguria.it", "lom.it", "lombardia.it", "lombardy.it", "lucania.it", "mar.it", "marche.it", "mol.it", "molise.it", "piedmont.it", "piemonte.it", "pmn.it", "pug.it", "puglia.it", "sar.it", "sardegna.it", "sardinia.it", "sic.it", "sicilia.it", "sicily.it", "taa.it", "tos.it", "toscana.it", "trentino-a-adige.it", "trentino-aadige.it", "trentino-alto-adige.it", "trentino-altoadige.it", "trentino-s-tirol.it", "trentino-stirol.it", "trentino-sud-tirol.it", "trentino-sudtirol.it", "trentino-sued-tirol.it", "trentino-suedtirol.it", "trentinoa-adige.it", "trentinoaadige.it", "trentinoalto-adige.it", "trentinoaltoadige.it", "trentinos-tirol.it", "trentinostirol.it", "trentinosud-tirol.it", "trentinosudtirol.it", "trentinosued-tirol.it", "trentinosuedtirol.it", "tuscany.it", "umb.it", "umbria.it", "val-d-aosta.it", "val-daosta.it", "vald-aosta.it", "valdaosta.it", "valle-aosta.it", "valle-d-aosta.it", "valle-daosta.it", "valleaosta.it", "valled-aosta.it", "valledaosta.it", "vallee-aoste.it", "valleeaoste.it", "vao.it", "vda.it", "ven.it", "veneto.it", "ag.it", "agrigento.it", "al.it", "alessandria.it", "alto-adige.it", "altoadige.it", "an.it", "ancona.it", "andria-barletta-trani.it", "andria-trani-barletta.it", "andriabarlettatrani.it", "andriatranibarletta.it", "ao.it", "aosta.it", "aoste.it", "ap.it", "aq.it", "aquila.it", "ar.it", "arezzo.it", "ascoli-piceno.it", "ascolipiceno.it", "asti.it", "at.it", "av.it", "avellino.it", "ba.it", "balsan.it", "bari.it", "barletta-trani-andria.it", "barlettatraniandria.it", "belluno.it", "benevento.it", "bergamo.it", "bg.it", "bi.it", "biella.it", "bl.it", "bn.it", "bo.it", "bologna.it", "bolzano.it", "bozen.it", "br.it", "brescia.it", "brindisi.it", "bs.it", "bt.it", "bz.it", "ca.it", "cagliari.it", "caltanissetta.it", "campidano-medio.it", "campidanomedio.it", "campobasso.it", "carbonia-iglesias.it", "carboniaiglesias.it", "carrara-massa.it", "carraramassa.it", "caserta.it", "catania.it", "catanzaro.it", "cb.it", "ce.it", "cesena-forli.it", "cesenaforli.it", "ch.it", "chieti.it", "ci.it", "cl.it", "cn.it", "co.it", "como.it", "cosenza.it", "cr.it", "cremona.it", "crotone.it", "cs.it", "ct.it", "cuneo.it", "cz.it", "dell-ogliastra.it", "dellogliastra.it", "en.it", "enna.it", "fc.it", "fe.it", "fermo.it", "ferrara.it", "fg.it", "fi.it", "firenze.it", "florence.it", "fm.it", "foggia.it", "forli-cesena.it", "forlicesena.it", "fr.it", "frosinone.it", "ge.it", "genoa.it", "genova.it", "go.it", "gorizia.it", "gr.it", "grosseto.it", "iglesias-carbonia.it", "iglesiascarbonia.it", "im.it", "imperia.it", "is.it", "isernia.it", "kr.it", "la-spezia.it", "laquila.it", "laspezia.it", "latina.it", "lc.it", "le.it", "lecce.it", "lecco.it", "li.it", "livorno.it", "lo.it", "lodi.it", "lt.it", "lu.it", "lucca.it", "macerata.it", "mantova.it", "massa-carrara.it", "massacarrara.it", "matera.it", "mb.it", "mc.it", "me.it", "medio-campidano.it", "mediocampidano.it", "messina.it", "mi.it", "milan.it", "milano.it", "mn.it", "mo.it", "modena.it", "monza-brianza.it", "monza-e-della-brianza.it", "monza.it", "monzabrianza.it", "monzaebrianza.it", "monzaedellabrianza.it", "ms.it", "mt.it", "na.it", "naples.it", "napoli.it", "no.it", "novara.it", "nu.it", "nuoro.it", "og.it", "ogliastra.it", "olbia-tempio.it", "olbiatempio.it", "or.it", "oristano.it", "ot.it", "pa.it", "padova.it", "padua.it", "palermo.it", "parma.it", "pavia.it", "pc.it", "pd.it", "pe.it", "perugia.it", "pesaro-urbino.it", "pesarourbino.it", "pescara.it", "pg.it", "pi.it", "piacenza.it", "pisa.it", "pistoia.it", "pn.it", "po.it", "pordenone.it", "potenza.it", "pr.it", "prato.it", "pt.it", "pu.it", "pv.it", "pz.it", "ra.it", "ragusa.it", "ravenna.it", "rc.it", "re.it", "reggio-calabria.it", "reggio-emilia.it", "reggiocalabria.it", "reggioemilia.it", "rg.it", "ri.it", "rieti.it", "rimini.it", "rm.it", "rn.it", "ro.it", "roma.it", "rome.it", "rovigo.it", "sa.it", "salerno.it", "sassari.it", "savona.it", "si.it", "siena.it", "siracusa.it", "so.it", "sondrio.it", "sp.it", "sr.it", "ss.it", "suedtirol.it", "sv.it", "ta.it", "taranto.it", "te.it", "tempio-olbia.it", "tempioolbia.it", "teramo.it", "terni.it", "tn.it", "to.it", "torino.it", "tp.it", "tr.it", "trani-andria-barletta.it", "trani-barletta-andria.it", "traniandriabarletta.it", "tranibarlettaandria.it", "trapani.it", "trentino.it", "trento.it", "treviso.it", "trieste.it", "ts.it", "turin.it", "tv.it", "ud.it", "udine.it", "urbino-pesaro.it", "urbinopesaro.it", "va.it", "varese.it", "vb.it", "vc.it", "ve.it", "venezia.it", "venice.it", "verbania.it", "vercelli.it", "verona.it", "vi.it", "vibo-valentia.it", "vibovalentia.it", "vicenza.it", "viterbo.it", "vr.it", "vs.it", "vt.it", "vv.it", "je", "co.je", "net.je", "org.je", "*.jm", "jo", "com.jo", "org.jo", "net.jo", "edu.jo", "sch.jo", "gov.jo", "mil.jo", "name.jo", "jobs", "jp", "ac.jp", "ad.jp", "co.jp", "ed.jp", "go.jp", "gr.jp", "lg.jp", "ne.jp", "or.jp", "aichi.jp", "akita.jp", "aomori.jp", "chiba.jp", "ehime.jp", "fukui.jp", "fukuoka.jp", "fukushima.jp", "gifu.jp", "gunma.jp", "hiroshima.jp", "hokkaido.jp", "hyogo.jp", "ibaraki.jp", "ishikawa.jp", "iwate.jp", "kagawa.jp", "kagoshima.jp", "kanagawa.jp", "kochi.jp", "kumamoto.jp", "kyoto.jp", "mie.jp", "miyagi.jp", "miyazaki.jp", "nagano.jp", "nagasaki.jp", "nara.jp", "niigata.jp", "oita.jp", "okayama.jp", "okinawa.jp", "osaka.jp", "saga.jp", "saitama.jp", "shiga.jp", "shimane.jp", "shizuoka.jp", "tochigi.jp", "tokushima.jp", "tokyo.jp", "tottori.jp", "toyama.jp", "wakayama.jp", "yamagata.jp", "yamaguchi.jp", "yamanashi.jp", "xn--4pvxs.jp", "xn--vgu402c.jp", "xn--c3s14m.jp", "xn--f6qx53a.jp", "xn--8pvr4u.jp", "xn--uist22h.jp", "xn--djrs72d6uy.jp", "xn--mkru45i.jp", "xn--0trq7p7nn.jp", "xn--8ltr62k.jp", "xn--2m4a15e.jp", "xn--efvn9s.jp", "xn--32vp30h.jp", "xn--4it797k.jp", "xn--1lqs71d.jp", "xn--5rtp49c.jp", "xn--5js045d.jp", "xn--ehqz56n.jp", "xn--1lqs03n.jp", "xn--qqqt11m.jp", "xn--kbrq7o.jp", "xn--pssu33l.jp", "xn--ntsq17g.jp", "xn--uisz3g.jp", "xn--6btw5a.jp", "xn--1ctwo.jp", "xn--6orx2r.jp", "xn--rht61e.jp", "xn--rht27z.jp", "xn--djty4k.jp", "xn--nit225k.jp", "xn--rht3d.jp", "xn--klty5x.jp", "xn--kltx9a.jp", "xn--kltp7d.jp", "xn--uuwu58a.jp", "xn--zbx025d.jp", "xn--ntso0iqx3a.jp", "xn--elqq16h.jp", "xn--4it168d.jp", "xn--klt787d.jp", "xn--rny31h.jp", "xn--7t0a264c.jp", "xn--5rtq34k.jp", "xn--k7yn95e.jp", "xn--tor131o.jp", "xn--d5qv7z876c.jp", "*.kawasaki.jp", "*.kitakyushu.jp", "*.kobe.jp", "*.nagoya.jp", "*.sapporo.jp", "*.sendai.jp", "*.yokohama.jp", "!city.kawasaki.jp", "!city.kitakyushu.jp", "!city.kobe.jp", "!city.nagoya.jp", "!city.sapporo.jp", "!city.sendai.jp", "!city.yokohama.jp", "aisai.aichi.jp", "ama.aichi.jp", "anjo.aichi.jp", "asuke.aichi.jp", "chiryu.aichi.jp", "chita.aichi.jp", "fuso.aichi.jp", "gamagori.aichi.jp", "handa.aichi.jp", "hazu.aichi.jp", "hekinan.aichi.jp", "higashiura.aichi.jp", "ichinomiya.aichi.jp", "inazawa.aichi.jp", "inuyama.aichi.jp", "isshiki.aichi.jp", "iwakura.aichi.jp", "kanie.aichi.jp", "kariya.aichi.jp", "kasugai.aichi.jp", "kira.aichi.jp", "kiyosu.aichi.jp", "komaki.aichi.jp", "konan.aichi.jp", "kota.aichi.jp", "mihama.aichi.jp", "miyoshi.aichi.jp", "nishio.aichi.jp", "nisshin.aichi.jp", "obu.aichi.jp", "oguchi.aichi.jp", "oharu.aichi.jp", "okazaki.aichi.jp", "owariasahi.aichi.jp", "seto.aichi.jp", "shikatsu.aichi.jp", "shinshiro.aichi.jp", "shitara.aichi.jp", "tahara.aichi.jp", "takahama.aichi.jp", "tobishima.aichi.jp", "toei.aichi.jp", "togo.aichi.jp", "tokai.aichi.jp", "tokoname.aichi.jp", "toyoake.aichi.jp", "toyohashi.aichi.jp", "toyokawa.aichi.jp", "toyone.aichi.jp", "toyota.aichi.jp", "tsushima.aichi.jp", "yatomi.aichi.jp", "akita.akita.jp", "daisen.akita.jp", "fujisato.akita.jp", "gojome.akita.jp", "hachirogata.akita.jp", "happou.akita.jp", "higashinaruse.akita.jp", "honjo.akita.jp", "honjyo.akita.jp", "ikawa.akita.jp", "kamikoani.akita.jp", "kamioka.akita.jp", "katagami.akita.jp", "kazuno.akita.jp", "kitaakita.akita.jp", "kosaka.akita.jp", "kyowa.akita.jp", "misato.akita.jp", "mitane.akita.jp", "moriyoshi.akita.jp", "nikaho.akita.jp", "noshiro.akita.jp", "odate.akita.jp", "oga.akita.jp", "ogata.akita.jp", "semboku.akita.jp", "yokote.akita.jp", "yurihonjo.akita.jp", "aomori.aomori.jp", "gonohe.aomori.jp", "hachinohe.aomori.jp", "hashikami.aomori.jp", "hiranai.aomori.jp", "hirosaki.aomori.jp", "itayanagi.aomori.jp", "kuroishi.aomori.jp", "misawa.aomori.jp", "mutsu.aomori.jp", "nakadomari.aomori.jp", "noheji.aomori.jp", "oirase.aomori.jp", "owani.aomori.jp", "rokunohe.aomori.jp", "sannohe.aomori.jp", "shichinohe.aomori.jp", "shingo.aomori.jp", "takko.aomori.jp", "towada.aomori.jp", "tsugaru.aomori.jp", "tsuruta.aomori.jp", "abiko.chiba.jp", "asahi.chiba.jp", "chonan.chiba.jp", "chosei.chiba.jp", "choshi.chiba.jp", "chuo.chiba.jp", "funabashi.chiba.jp", "futtsu.chiba.jp", "hanamigawa.chiba.jp", "ichihara.chiba.jp", "ichikawa.chiba.jp", "ichinomiya.chiba.jp", "inzai.chiba.jp", "isumi.chiba.jp", "kamagaya.chiba.jp", "kamogawa.chiba.jp", "kashiwa.chiba.jp", "katori.chiba.jp", "katsuura.chiba.jp", "kimitsu.chiba.jp", "kisarazu.chiba.jp", "kozaki.chiba.jp", "kujukuri.chiba.jp", "kyonan.chiba.jp", "matsudo.chiba.jp", "midori.chiba.jp", "mihama.chiba.jp", "minamiboso.chiba.jp", "mobara.chiba.jp", "mutsuzawa.chiba.jp", "nagara.chiba.jp", "nagareyama.chiba.jp", "narashino.chiba.jp", "narita.chiba.jp", "noda.chiba.jp", "oamishirasato.chiba.jp", "omigawa.chiba.jp", "onjuku.chiba.jp", "otaki.chiba.jp", "sakae.chiba.jp", "sakura.chiba.jp", "shimofusa.chiba.jp", "shirako.chiba.jp", "shiroi.chiba.jp", "shisui.chiba.jp", "sodegaura.chiba.jp", "sosa.chiba.jp", "tako.chiba.jp", "tateyama.chiba.jp", "togane.chiba.jp", "tohnosho.chiba.jp", "tomisato.chiba.jp", "urayasu.chiba.jp", "yachimata.chiba.jp", "yachiyo.chiba.jp", "yokaichiba.chiba.jp", "yokoshibahikari.chiba.jp", "yotsukaido.chiba.jp", "ainan.ehime.jp", "honai.ehime.jp", "ikata.ehime.jp", "imabari.ehime.jp", "iyo.ehime.jp", "kamijima.ehime.jp", "kihoku.ehime.jp", "kumakogen.ehime.jp", "masaki.ehime.jp", "matsuno.ehime.jp", "matsuyama.ehime.jp", "namikata.ehime.jp", "niihama.ehime.jp", "ozu.ehime.jp", "saijo.ehime.jp", "seiyo.ehime.jp", "shikokuchuo.ehime.jp", "tobe.ehime.jp", "toon.ehime.jp", "uchiko.ehime.jp", "uwajima.ehime.jp", "yawatahama.ehime.jp", "echizen.fukui.jp", "eiheiji.fukui.jp", "fukui.fukui.jp", "ikeda.fukui.jp", "katsuyama.fukui.jp", "mihama.fukui.jp", "minamiechizen.fukui.jp", "obama.fukui.jp", "ohi.fukui.jp", "ono.fukui.jp", "sabae.fukui.jp", "sakai.fukui.jp", "takahama.fukui.jp", "tsuruga.fukui.jp", "wakasa.fukui.jp", "ashiya.fukuoka.jp", "buzen.fukuoka.jp", "chikugo.fukuoka.jp", "chikuho.fukuoka.jp", "chikujo.fukuoka.jp", "chikushino.fukuoka.jp", "chikuzen.fukuoka.jp", "chuo.fukuoka.jp", "dazaifu.fukuoka.jp", "fukuchi.fukuoka.jp", "hakata.fukuoka.jp", "higashi.fukuoka.jp", "hirokawa.fukuoka.jp", "hisayama.fukuoka.jp", "iizuka.fukuoka.jp", "inatsuki.fukuoka.jp", "kaho.fukuoka.jp", "kasuga.fukuoka.jp", "kasuya.fukuoka.jp", "kawara.fukuoka.jp", "keisen.fukuoka.jp", "koga.fukuoka.jp", "kurate.fukuoka.jp", "kurogi.fukuoka.jp", "kurume.fukuoka.jp", "minami.fukuoka.jp", "miyako.fukuoka.jp", "miyama.fukuoka.jp", "miyawaka.fukuoka.jp", "mizumaki.fukuoka.jp", "munakata.fukuoka.jp", "nakagawa.fukuoka.jp", "nakama.fukuoka.jp", "nishi.fukuoka.jp", "nogata.fukuoka.jp", "ogori.fukuoka.jp", "okagaki.fukuoka.jp", "okawa.fukuoka.jp", "oki.fukuoka.jp", "omuta.fukuoka.jp", "onga.fukuoka.jp", "onojo.fukuoka.jp", "oto.fukuoka.jp", "saigawa.fukuoka.jp", "sasaguri.fukuoka.jp", "shingu.fukuoka.jp", "shinyoshitomi.fukuoka.jp", "shonai.fukuoka.jp", "soeda.fukuoka.jp", "sue.fukuoka.jp", "tachiarai.fukuoka.jp", "tagawa.fukuoka.jp", "takata.fukuoka.jp", "toho.fukuoka.jp", "toyotsu.fukuoka.jp", "tsuiki.fukuoka.jp", "ukiha.fukuoka.jp", "umi.fukuoka.jp", "usui.fukuoka.jp", "yamada.fukuoka.jp", "yame.fukuoka.jp", "yanagawa.fukuoka.jp", "yukuhashi.fukuoka.jp", "aizubange.fukushima.jp", "aizumisato.fukushima.jp", "aizuwakamatsu.fukushima.jp", "asakawa.fukushima.jp", "bandai.fukushima.jp", "date.fukushima.jp", "fukushima.fukushima.jp", "furudono.fukushima.jp", "futaba.fukushima.jp", "hanawa.fukushima.jp", "higashi.fukushima.jp", "hirata.fukushima.jp", "hirono.fukushima.jp", "iitate.fukushima.jp", "inawashiro.fukushima.jp", "ishikawa.fukushima.jp", "iwaki.fukushima.jp", "izumizaki.fukushima.jp", "kagamiishi.fukushima.jp", "kaneyama.fukushima.jp", "kawamata.fukushima.jp", "kitakata.fukushima.jp", "kitashiobara.fukushima.jp", "koori.fukushima.jp", "koriyama.fukushima.jp", "kunimi.fukushima.jp", "miharu.fukushima.jp", "mishima.fukushima.jp", "namie.fukushima.jp", "nango.fukushima.jp", "nishiaizu.fukushima.jp", "nishigo.fukushima.jp", "okuma.fukushima.jp", "omotego.fukushima.jp", "ono.fukushima.jp", "otama.fukushima.jp", "samegawa.fukushima.jp", "shimogo.fukushima.jp", "shirakawa.fukushima.jp", "showa.fukushima.jp", "soma.fukushima.jp", "sukagawa.fukushima.jp", "taishin.fukushima.jp", "tamakawa.fukushima.jp", "tanagura.fukushima.jp", "tenei.fukushima.jp", "yabuki.fukushima.jp", "yamato.fukushima.jp", "yamatsuri.fukushima.jp", "yanaizu.fukushima.jp", "yugawa.fukushima.jp", "anpachi.gifu.jp", "ena.gifu.jp", "gifu.gifu.jp", "ginan.gifu.jp", "godo.gifu.jp", "gujo.gifu.jp", "hashima.gifu.jp", "hichiso.gifu.jp", "hida.gifu.jp", "higashishirakawa.gifu.jp", "ibigawa.gifu.jp", "ikeda.gifu.jp", "kakamigahara.gifu.jp", "kani.gifu.jp", "kasahara.gifu.jp", "kasamatsu.gifu.jp", "kawaue.gifu.jp", "kitagata.gifu.jp", "mino.gifu.jp", "minokamo.gifu.jp", "mitake.gifu.jp", "mizunami.gifu.jp", "motosu.gifu.jp", "nakatsugawa.gifu.jp", "ogaki.gifu.jp", "sakahogi.gifu.jp", "seki.gifu.jp", "sekigahara.gifu.jp", "shirakawa.gifu.jp", "tajimi.gifu.jp", "takayama.gifu.jp", "tarui.gifu.jp", "toki.gifu.jp", "tomika.gifu.jp", "wanouchi.gifu.jp", "yamagata.gifu.jp", "yaotsu.gifu.jp", "yoro.gifu.jp", "annaka.gunma.jp", "chiyoda.gunma.jp", "fujioka.gunma.jp", "higashiagatsuma.gunma.jp", "isesaki.gunma.jp", "itakura.gunma.jp", "kanna.gunma.jp", "kanra.gunma.jp", "katashina.gunma.jp", "kawaba.gunma.jp", "kiryu.gunma.jp", "kusatsu.gunma.jp", "maebashi.gunma.jp", "meiwa.gunma.jp", "midori.gunma.jp", "minakami.gunma.jp", "naganohara.gunma.jp", "nakanojo.gunma.jp", "nanmoku.gunma.jp", "numata.gunma.jp", "oizumi.gunma.jp", "ora.gunma.jp", "ota.gunma.jp", "shibukawa.gunma.jp", "shimonita.gunma.jp", "shinto.gunma.jp", "showa.gunma.jp", "takasaki.gunma.jp", "takayama.gunma.jp", "tamamura.gunma.jp", "tatebayashi.gunma.jp", "tomioka.gunma.jp", "tsukiyono.gunma.jp", "tsumagoi.gunma.jp", "ueno.gunma.jp", "yoshioka.gunma.jp", "asaminami.hiroshima.jp", "daiwa.hiroshima.jp", "etajima.hiroshima.jp", "fuchu.hiroshima.jp", "fukuyama.hiroshima.jp", "hatsukaichi.hiroshima.jp", "higashihiroshima.hiroshima.jp", "hongo.hiroshima.jp", "jinsekikogen.hiroshima.jp", "kaita.hiroshima.jp", "kui.hiroshima.jp", "kumano.hiroshima.jp", "kure.hiroshima.jp", "mihara.hiroshima.jp", "miyoshi.hiroshima.jp", "naka.hiroshima.jp", "onomichi.hiroshima.jp", "osakikamijima.hiroshima.jp", "otake.hiroshima.jp", "saka.hiroshima.jp", "sera.hiroshima.jp", "seranishi.hiroshima.jp", "shinichi.hiroshima.jp", "shobara.hiroshima.jp", "takehara.hiroshima.jp", "abashiri.hokkaido.jp", "abira.hokkaido.jp", "aibetsu.hokkaido.jp", "akabira.hokkaido.jp", "akkeshi.hokkaido.jp", "asahikawa.hokkaido.jp", "ashibetsu.hokkaido.jp", "ashoro.hokkaido.jp", "assabu.hokkaido.jp", "atsuma.hokkaido.jp", "bibai.hokkaido.jp", "biei.hokkaido.jp", "bifuka.hokkaido.jp", "bihoro.hokkaido.jp", "biratori.hokkaido.jp", "chippubetsu.hokkaido.jp", "chitose.hokkaido.jp", "date.hokkaido.jp", "ebetsu.hokkaido.jp", "embetsu.hokkaido.jp", "eniwa.hokkaido.jp", "erimo.hokkaido.jp", "esan.hokkaido.jp", "esashi.hokkaido.jp", "fukagawa.hokkaido.jp", "fukushima.hokkaido.jp", "furano.hokkaido.jp", "furubira.hokkaido.jp", "haboro.hokkaido.jp", "hakodate.hokkaido.jp", "hamatonbetsu.hokkaido.jp", "hidaka.hokkaido.jp", "higashikagura.hokkaido.jp", "higashikawa.hokkaido.jp", "hiroo.hokkaido.jp", "hokuryu.hokkaido.jp", "hokuto.hokkaido.jp", "honbetsu.hokkaido.jp", "horokanai.hokkaido.jp", "horonobe.hokkaido.jp", "ikeda.hokkaido.jp", "imakane.hokkaido.jp", "ishikari.hokkaido.jp", "iwamizawa.hokkaido.jp", "iwanai.hokkaido.jp", "kamifurano.hokkaido.jp", "kamikawa.hokkaido.jp", "kamishihoro.hokkaido.jp", "kamisunagawa.hokkaido.jp", "kamoenai.hokkaido.jp", "kayabe.hokkaido.jp", "kembuchi.hokkaido.jp", "kikonai.hokkaido.jp", "kimobetsu.hokkaido.jp", "kitahiroshima.hokkaido.jp", "kitami.hokkaido.jp", "kiyosato.hokkaido.jp", "koshimizu.hokkaido.jp", "kunneppu.hokkaido.jp", "kuriyama.hokkaido.jp", "kuromatsunai.hokkaido.jp", "kushiro.hokkaido.jp", "kutchan.hokkaido.jp", "kyowa.hokkaido.jp", "mashike.hokkaido.jp", "matsumae.hokkaido.jp", "mikasa.hokkaido.jp", "minamifurano.hokkaido.jp", "mombetsu.hokkaido.jp", "moseushi.hokkaido.jp", "mukawa.hokkaido.jp", "muroran.hokkaido.jp", "naie.hokkaido.jp", "nakagawa.hokkaido.jp", "nakasatsunai.hokkaido.jp", "nakatombetsu.hokkaido.jp", "nanae.hokkaido.jp", "nanporo.hokkaido.jp", "nayoro.hokkaido.jp", "nemuro.hokkaido.jp", "niikappu.hokkaido.jp", "niki.hokkaido.jp", "nishiokoppe.hokkaido.jp", "noboribetsu.hokkaido.jp", "numata.hokkaido.jp", "obihiro.hokkaido.jp", "obira.hokkaido.jp", "oketo.hokkaido.jp", "okoppe.hokkaido.jp", "otaru.hokkaido.jp", "otobe.hokkaido.jp", "otofuke.hokkaido.jp", "otoineppu.hokkaido.jp", "oumu.hokkaido.jp", "ozora.hokkaido.jp", "pippu.hokkaido.jp", "rankoshi.hokkaido.jp", "rebun.hokkaido.jp", "rikubetsu.hokkaido.jp", "rishiri.hokkaido.jp", "rishirifuji.hokkaido.jp", "saroma.hokkaido.jp", "sarufutsu.hokkaido.jp", "shakotan.hokkaido.jp", "shari.hokkaido.jp", "shibecha.hokkaido.jp", "shibetsu.hokkaido.jp", "shikabe.hokkaido.jp", "shikaoi.hokkaido.jp", "shimamaki.hokkaido.jp", "shimizu.hokkaido.jp", "shimokawa.hokkaido.jp", "shinshinotsu.hokkaido.jp", "shintoku.hokkaido.jp", "shiranuka.hokkaido.jp", "shiraoi.hokkaido.jp", "shiriuchi.hokkaido.jp", "sobetsu.hokkaido.jp", "sunagawa.hokkaido.jp", "taiki.hokkaido.jp", "takasu.hokkaido.jp", "takikawa.hokkaido.jp", "takinoue.hokkaido.jp", "teshikaga.hokkaido.jp", "tobetsu.hokkaido.jp", "tohma.hokkaido.jp", "tomakomai.hokkaido.jp", "tomari.hokkaido.jp", "toya.hokkaido.jp", "toyako.hokkaido.jp", "toyotomi.hokkaido.jp", "toyoura.hokkaido.jp", "tsubetsu.hokkaido.jp", "tsukigata.hokkaido.jp", "urakawa.hokkaido.jp", "urausu.hokkaido.jp", "uryu.hokkaido.jp", "utashinai.hokkaido.jp", "wakkanai.hokkaido.jp", "wassamu.hokkaido.jp", "yakumo.hokkaido.jp", "yoichi.hokkaido.jp", "aioi.hyogo.jp", "akashi.hyogo.jp", "ako.hyogo.jp", "amagasaki.hyogo.jp", "aogaki.hyogo.jp", "asago.hyogo.jp", "ashiya.hyogo.jp", "awaji.hyogo.jp", "fukusaki.hyogo.jp", "goshiki.hyogo.jp", "harima.hyogo.jp", "himeji.hyogo.jp", "ichikawa.hyogo.jp", "inagawa.hyogo.jp", "itami.hyogo.jp", "kakogawa.hyogo.jp", "kamigori.hyogo.jp", "kamikawa.hyogo.jp", "kasai.hyogo.jp", "kasuga.hyogo.jp", "kawanishi.hyogo.jp", "miki.hyogo.jp", "minamiawaji.hyogo.jp", "nishinomiya.hyogo.jp", "nishiwaki.hyogo.jp", "ono.hyogo.jp", "sanda.hyogo.jp", "sannan.hyogo.jp", "sasayama.hyogo.jp", "sayo.hyogo.jp", "shingu.hyogo.jp", "shinonsen.hyogo.jp", "shiso.hyogo.jp", "sumoto.hyogo.jp", "taishi.hyogo.jp", "taka.hyogo.jp", "takarazuka.hyogo.jp", "takasago.hyogo.jp", "takino.hyogo.jp", "tamba.hyogo.jp", "tatsuno.hyogo.jp", "toyooka.hyogo.jp", "yabu.hyogo.jp", "yashiro.hyogo.jp", "yoka.hyogo.jp", "yokawa.hyogo.jp", "ami.ibaraki.jp", "asahi.ibaraki.jp", "bando.ibaraki.jp", "chikusei.ibaraki.jp", "daigo.ibaraki.jp", "fujishiro.ibaraki.jp", "hitachi.ibaraki.jp", "hitachinaka.ibaraki.jp", "hitachiomiya.ibaraki.jp", "hitachiota.ibaraki.jp", "ibaraki.ibaraki.jp", "ina.ibaraki.jp", "inashiki.ibaraki.jp", "itako.ibaraki.jp", "iwama.ibaraki.jp", "joso.ibaraki.jp", "kamisu.ibaraki.jp", "kasama.ibaraki.jp", "kashima.ibaraki.jp", "kasumigaura.ibaraki.jp", "koga.ibaraki.jp", "miho.ibaraki.jp", "mito.ibaraki.jp", "moriya.ibaraki.jp", "naka.ibaraki.jp", "namegata.ibaraki.jp", "oarai.ibaraki.jp", "ogawa.ibaraki.jp", "omitama.ibaraki.jp", "ryugasaki.ibaraki.jp", "sakai.ibaraki.jp", "sakuragawa.ibaraki.jp", "shimodate.ibaraki.jp", "shimotsuma.ibaraki.jp", "shirosato.ibaraki.jp", "sowa.ibaraki.jp", "suifu.ibaraki.jp", "takahagi.ibaraki.jp", "tamatsukuri.ibaraki.jp", "tokai.ibaraki.jp", "tomobe.ibaraki.jp", "tone.ibaraki.jp", "toride.ibaraki.jp", "tsuchiura.ibaraki.jp", "tsukuba.ibaraki.jp", "uchihara.ibaraki.jp", "ushiku.ibaraki.jp", "yachiyo.ibaraki.jp", "yamagata.ibaraki.jp", "yawara.ibaraki.jp", "yuki.ibaraki.jp", "anamizu.ishikawa.jp", "hakui.ishikawa.jp", "hakusan.ishikawa.jp", "kaga.ishikawa.jp", "kahoku.ishikawa.jp", "kanazawa.ishikawa.jp", "kawakita.ishikawa.jp", "komatsu.ishikawa.jp", "nakanoto.ishikawa.jp", "nanao.ishikawa.jp", "nomi.ishikawa.jp", "nonoichi.ishikawa.jp", "noto.ishikawa.jp", "shika.ishikawa.jp", "suzu.ishikawa.jp", "tsubata.ishikawa.jp", "tsurugi.ishikawa.jp", "uchinada.ishikawa.jp", "wajima.ishikawa.jp", "fudai.iwate.jp", "fujisawa.iwate.jp", "hanamaki.iwate.jp", "hiraizumi.iwate.jp", "hirono.iwate.jp", "ichinohe.iwate.jp", "ichinoseki.iwate.jp", "iwaizumi.iwate.jp", "iwate.iwate.jp", "joboji.iwate.jp", "kamaishi.iwate.jp", "kanegasaki.iwate.jp", "karumai.iwate.jp", "kawai.iwate.jp", "kitakami.iwate.jp", "kuji.iwate.jp", "kunohe.iwate.jp", "kuzumaki.iwate.jp", "miyako.iwate.jp", "mizusawa.iwate.jp", "morioka.iwate.jp", "ninohe.iwate.jp", "noda.iwate.jp", "ofunato.iwate.jp", "oshu.iwate.jp", "otsuchi.iwate.jp", "rikuzentakata.iwate.jp", "shiwa.iwate.jp", "shizukuishi.iwate.jp", "sumita.iwate.jp", "tanohata.iwate.jp", "tono.iwate.jp", "yahaba.iwate.jp", "yamada.iwate.jp", "ayagawa.kagawa.jp", "higashikagawa.kagawa.jp", "kanonji.kagawa.jp", "kotohira.kagawa.jp", "manno.kagawa.jp", "marugame.kagawa.jp", "mitoyo.kagawa.jp", "naoshima.kagawa.jp", "sanuki.kagawa.jp", "tadotsu.kagawa.jp", "takamatsu.kagawa.jp", "tonosho.kagawa.jp", "uchinomi.kagawa.jp", "utazu.kagawa.jp", "zentsuji.kagawa.jp", "akune.kagoshima.jp", "amami.kagoshima.jp", "hioki.kagoshima.jp", "isa.kagoshima.jp", "isen.kagoshima.jp", "izumi.kagoshima.jp", "kagoshima.kagoshima.jp", "kanoya.kagoshima.jp", "kawanabe.kagoshima.jp", "kinko.kagoshima.jp", "kouyama.kagoshima.jp", "makurazaki.kagoshima.jp", "matsumoto.kagoshima.jp", "minamitane.kagoshima.jp", "nakatane.kagoshima.jp", "nishinoomote.kagoshima.jp", "satsumasendai.kagoshima.jp", "soo.kagoshima.jp", "tarumizu.kagoshima.jp", "yusui.kagoshima.jp", "aikawa.kanagawa.jp", "atsugi.kanagawa.jp", "ayase.kanagawa.jp", "chigasaki.kanagawa.jp", "ebina.kanagawa.jp", "fujisawa.kanagawa.jp", "hadano.kanagawa.jp", "hakone.kanagawa.jp", "hiratsuka.kanagawa.jp", "isehara.kanagawa.jp", "kaisei.kanagawa.jp", "kamakura.kanagawa.jp", "kiyokawa.kanagawa.jp", "matsuda.kanagawa.jp", "minamiashigara.kanagawa.jp", "miura.kanagawa.jp", "nakai.kanagawa.jp", "ninomiya.kanagawa.jp", "odawara.kanagawa.jp", "oi.kanagawa.jp", "oiso.kanagawa.jp", "sagamihara.kanagawa.jp", "samukawa.kanagawa.jp", "tsukui.kanagawa.jp", "yamakita.kanagawa.jp", "yamato.kanagawa.jp", "yokosuka.kanagawa.jp", "yugawara.kanagawa.jp", "zama.kanagawa.jp", "zushi.kanagawa.jp", "aki.kochi.jp", "geisei.kochi.jp", "hidaka.kochi.jp", "higashitsuno.kochi.jp", "ino.kochi.jp", "kagami.kochi.jp", "kami.kochi.jp", "kitagawa.kochi.jp", "kochi.kochi.jp", "mihara.kochi.jp", "motoyama.kochi.jp", "muroto.kochi.jp", "nahari.kochi.jp", "nakamura.kochi.jp", "nankoku.kochi.jp", "nishitosa.kochi.jp", "niyodogawa.kochi.jp", "ochi.kochi.jp", "okawa.kochi.jp", "otoyo.kochi.jp", "otsuki.kochi.jp", "sakawa.kochi.jp", "sukumo.kochi.jp", "susaki.kochi.jp", "tosa.kochi.jp", "tosashimizu.kochi.jp", "toyo.kochi.jp", "tsuno.kochi.jp", "umaji.kochi.jp", "yasuda.kochi.jp", "yusuhara.kochi.jp", "amakusa.kumamoto.jp", "arao.kumamoto.jp", "aso.kumamoto.jp", "choyo.kumamoto.jp", "gyokuto.kumamoto.jp", "hitoyoshi.kumamoto.jp", "kamiamakusa.kumamoto.jp", "kashima.kumamoto.jp", "kikuchi.kumamoto.jp", "kosa.kumamoto.jp", "kumamoto.kumamoto.jp", "mashiki.kumamoto.jp", "mifune.kumamoto.jp", "minamata.kumamoto.jp", "minamioguni.kumamoto.jp", "nagasu.kumamoto.jp", "nishihara.kumamoto.jp", "oguni.kumamoto.jp", "ozu.kumamoto.jp", "sumoto.kumamoto.jp", "takamori.kumamoto.jp", "uki.kumamoto.jp", "uto.kumamoto.jp", "yamaga.kumamoto.jp", "yamato.kumamoto.jp", "yatsushiro.kumamoto.jp", "ayabe.kyoto.jp", "fukuchiyama.kyoto.jp", "higashiyama.kyoto.jp", "ide.kyoto.jp", "ine.kyoto.jp", "joyo.kyoto.jp", "kameoka.kyoto.jp", "kamo.kyoto.jp", "kita.kyoto.jp", "kizu.kyoto.jp", "kumiyama.kyoto.jp", "kyotamba.kyoto.jp", "kyotanabe.kyoto.jp", "kyotango.kyoto.jp", "maizuru.kyoto.jp", "minami.kyoto.jp", "minamiyamashiro.kyoto.jp", "miyazu.kyoto.jp", "muko.kyoto.jp", "nagaokakyo.kyoto.jp", "nakagyo.kyoto.jp", "nantan.kyoto.jp", "oyamazaki.kyoto.jp", "sakyo.kyoto.jp", "seika.kyoto.jp", "tanabe.kyoto.jp", "uji.kyoto.jp", "ujitawara.kyoto.jp", "wazuka.kyoto.jp", "yamashina.kyoto.jp", "yawata.kyoto.jp", "asahi.mie.jp", "inabe.mie.jp", "ise.mie.jp", "kameyama.mie.jp", "kawagoe.mie.jp", "kiho.mie.jp", "kisosaki.mie.jp", "kiwa.mie.jp", "komono.mie.jp", "kumano.mie.jp", "kuwana.mie.jp", "matsusaka.mie.jp", "meiwa.mie.jp", "mihama.mie.jp", "minamiise.mie.jp", "misugi.mie.jp", "miyama.mie.jp", "nabari.mie.jp", "shima.mie.jp", "suzuka.mie.jp", "tado.mie.jp", "taiki.mie.jp", "taki.mie.jp", "tamaki.mie.jp", "toba.mie.jp", "tsu.mie.jp", "udono.mie.jp", "ureshino.mie.jp", "watarai.mie.jp", "yokkaichi.mie.jp", "furukawa.miyagi.jp", "higashimatsushima.miyagi.jp", "ishinomaki.miyagi.jp", "iwanuma.miyagi.jp", "kakuda.miyagi.jp", "kami.miyagi.jp", "kawasaki.miyagi.jp", "kesennuma.miyagi.jp", "marumori.miyagi.jp", "matsushima.miyagi.jp", "minamisanriku.miyagi.jp", "misato.miyagi.jp", "murata.miyagi.jp", "natori.miyagi.jp", "ogawara.miyagi.jp", "ohira.miyagi.jp", "onagawa.miyagi.jp", "osaki.miyagi.jp", "rifu.miyagi.jp", "semine.miyagi.jp", "shibata.miyagi.jp", "shichikashuku.miyagi.jp", "shikama.miyagi.jp", "shiogama.miyagi.jp", "shiroishi.miyagi.jp", "tagajo.miyagi.jp", "taiwa.miyagi.jp", "tome.miyagi.jp", "tomiya.miyagi.jp", "wakuya.miyagi.jp", "watari.miyagi.jp", "yamamoto.miyagi.jp", "zao.miyagi.jp", "aya.miyazaki.jp", "ebino.miyazaki.jp", "gokase.miyazaki.jp", "hyuga.miyazaki.jp", "kadogawa.miyazaki.jp", "kawaminami.miyazaki.jp", "kijo.miyazaki.jp", "kitagawa.miyazaki.jp", "kitakata.miyazaki.jp", "kitaura.miyazaki.jp", "kobayashi.miyazaki.jp", "kunitomi.miyazaki.jp", "kushima.miyazaki.jp", "mimata.miyazaki.jp", "miyakonojo.miyazaki.jp", "miyazaki.miyazaki.jp", "morotsuka.miyazaki.jp", "nichinan.miyazaki.jp", "nishimera.miyazaki.jp", "nobeoka.miyazaki.jp", "saito.miyazaki.jp", "shiiba.miyazaki.jp", "shintomi.miyazaki.jp", "takaharu.miyazaki.jp", "takanabe.miyazaki.jp", "takazaki.miyazaki.jp", "tsuno.miyazaki.jp", "achi.nagano.jp", "agematsu.nagano.jp", "anan.nagano.jp", "aoki.nagano.jp", "asahi.nagano.jp", "azumino.nagano.jp", "chikuhoku.nagano.jp", "chikuma.nagano.jp", "chino.nagano.jp", "fujimi.nagano.jp", "hakuba.nagano.jp", "hara.nagano.jp", "hiraya.nagano.jp", "iida.nagano.jp", "iijima.nagano.jp", "iiyama.nagano.jp", "iizuna.nagano.jp", "ikeda.nagano.jp", "ikusaka.nagano.jp", "ina.nagano.jp", "karuizawa.nagano.jp", "kawakami.nagano.jp", "kiso.nagano.jp", "kisofukushima.nagano.jp", "kitaaiki.nagano.jp", "komagane.nagano.jp", "komoro.nagano.jp", "matsukawa.nagano.jp", "matsumoto.nagano.jp", "miasa.nagano.jp", "minamiaiki.nagano.jp", "minamimaki.nagano.jp", "minamiminowa.nagano.jp", "minowa.nagano.jp", "miyada.nagano.jp", "miyota.nagano.jp", "mochizuki.nagano.jp", "nagano.nagano.jp", "nagawa.nagano.jp", "nagiso.nagano.jp", "nakagawa.nagano.jp", "nakano.nagano.jp", "nozawaonsen.nagano.jp", "obuse.nagano.jp", "ogawa.nagano.jp", "okaya.nagano.jp", "omachi.nagano.jp", "omi.nagano.jp", "ookuwa.nagano.jp", "ooshika.nagano.jp", "otaki.nagano.jp", "otari.nagano.jp", "sakae.nagano.jp", "sakaki.nagano.jp", "saku.nagano.jp", "sakuho.nagano.jp", "shimosuwa.nagano.jp", "shinanomachi.nagano.jp", "shiojiri.nagano.jp", "suwa.nagano.jp", "suzaka.nagano.jp", "takagi.nagano.jp", "takamori.nagano.jp", "takayama.nagano.jp", "tateshina.nagano.jp", "tatsuno.nagano.jp", "togakushi.nagano.jp", "togura.nagano.jp", "tomi.nagano.jp", "ueda.nagano.jp", "wada.nagano.jp", "yamagata.nagano.jp", "yamanouchi.nagano.jp", "yasaka.nagano.jp", "yasuoka.nagano.jp", "chijiwa.nagasaki.jp", "futsu.nagasaki.jp", "goto.nagasaki.jp", "hasami.nagasaki.jp", "hirado.nagasaki.jp", "iki.nagasaki.jp", "isahaya.nagasaki.jp", "kawatana.nagasaki.jp", "kuchinotsu.nagasaki.jp", "matsuura.nagasaki.jp", "nagasaki.nagasaki.jp", "obama.nagasaki.jp", "omura.nagasaki.jp", "oseto.nagasaki.jp", "saikai.nagasaki.jp", "sasebo.nagasaki.jp", "seihi.nagasaki.jp", "shimabara.nagasaki.jp", "shinkamigoto.nagasaki.jp", "togitsu.nagasaki.jp", "tsushima.nagasaki.jp", "unzen.nagasaki.jp", "ando.nara.jp", "gose.nara.jp", "heguri.nara.jp", "higashiyoshino.nara.jp", "ikaruga.nara.jp", "ikoma.nara.jp", "kamikitayama.nara.jp", "kanmaki.nara.jp", "kashiba.nara.jp", "kashihara.nara.jp", "katsuragi.nara.jp", "kawai.nara.jp", "kawakami.nara.jp", "kawanishi.nara.jp", "koryo.nara.jp", "kurotaki.nara.jp", "mitsue.nara.jp", "miyake.nara.jp", "nara.nara.jp", "nosegawa.nara.jp", "oji.nara.jp", "ouda.nara.jp", "oyodo.nara.jp", "sakurai.nara.jp", "sango.nara.jp", "shimoichi.nara.jp", "shimokitayama.nara.jp", "shinjo.nara.jp", "soni.nara.jp", "takatori.nara.jp", "tawaramoto.nara.jp", "tenkawa.nara.jp", "tenri.nara.jp", "uda.nara.jp", "yamatokoriyama.nara.jp", "yamatotakada.nara.jp", "yamazoe.nara.jp", "yoshino.nara.jp", "aga.niigata.jp", "agano.niigata.jp", "gosen.niigata.jp", "itoigawa.niigata.jp", "izumozaki.niigata.jp", "joetsu.niigata.jp", "kamo.niigata.jp", "kariwa.niigata.jp", "kashiwazaki.niigata.jp", "minamiuonuma.niigata.jp", "mitsuke.niigata.jp", "muika.niigata.jp", "murakami.niigata.jp", "myoko.niigata.jp", "nagaoka.niigata.jp", "niigata.niigata.jp", "ojiya.niigata.jp", "omi.niigata.jp", "sado.niigata.jp", "sanjo.niigata.jp", "seiro.niigata.jp", "seirou.niigata.jp", "sekikawa.niigata.jp", "shibata.niigata.jp", "tagami.niigata.jp", "tainai.niigata.jp", "tochio.niigata.jp", "tokamachi.niigata.jp", "tsubame.niigata.jp", "tsunan.niigata.jp", "uonuma.niigata.jp", "yahiko.niigata.jp", "yoita.niigata.jp", "yuzawa.niigata.jp", "beppu.oita.jp", "bungoono.oita.jp", "bungotakada.oita.jp", "hasama.oita.jp", "hiji.oita.jp", "himeshima.oita.jp", "hita.oita.jp", "kamitsue.oita.jp", "kokonoe.oita.jp", "kuju.oita.jp", "kunisaki.oita.jp", "kusu.oita.jp", "oita.oita.jp", "saiki.oita.jp", "taketa.oita.jp", "tsukumi.oita.jp", "usa.oita.jp", "usuki.oita.jp", "yufu.oita.jp", "akaiwa.okayama.jp", "asakuchi.okayama.jp", "bizen.okayama.jp", "hayashima.okayama.jp", "ibara.okayama.jp", "kagamino.okayama.jp", "kasaoka.okayama.jp", "kibichuo.okayama.jp", "kumenan.okayama.jp", "kurashiki.okayama.jp", "maniwa.okayama.jp", "misaki.okayama.jp", "nagi.okayama.jp", "niimi.okayama.jp", "nishiawakura.okayama.jp", "okayama.okayama.jp", "satosho.okayama.jp", "setouchi.okayama.jp", "shinjo.okayama.jp", "shoo.okayama.jp", "soja.okayama.jp", "takahashi.okayama.jp", "tamano.okayama.jp", "tsuyama.okayama.jp", "wake.okayama.jp", "yakage.okayama.jp", "aguni.okinawa.jp", "ginowan.okinawa.jp", "ginoza.okinawa.jp", "gushikami.okinawa.jp", "haebaru.okinawa.jp", "higashi.okinawa.jp", "hirara.okinawa.jp", "iheya.okinawa.jp", "ishigaki.okinawa.jp", "ishikawa.okinawa.jp", "itoman.okinawa.jp", "izena.okinawa.jp", "kadena.okinawa.jp", "kin.okinawa.jp", "kitadaito.okinawa.jp", "kitanakagusuku.okinawa.jp", "kumejima.okinawa.jp", "kunigami.okinawa.jp", "minamidaito.okinawa.jp", "motobu.okinawa.jp", "nago.okinawa.jp", "naha.okinawa.jp", "nakagusuku.okinawa.jp", "nakijin.okinawa.jp", "nanjo.okinawa.jp", "nishihara.okinawa.jp", "ogimi.okinawa.jp", "okinawa.okinawa.jp", "onna.okinawa.jp", "shimoji.okinawa.jp", "taketomi.okinawa.jp", "tarama.okinawa.jp", "tokashiki.okinawa.jp", "tomigusuku.okinawa.jp", "tonaki.okinawa.jp", "urasoe.okinawa.jp", "uruma.okinawa.jp", "yaese.okinawa.jp", "yomitan.okinawa.jp", "yonabaru.okinawa.jp", "yonaguni.okinawa.jp", "zamami.okinawa.jp", "abeno.osaka.jp", "chihayaakasaka.osaka.jp", "chuo.osaka.jp", "daito.osaka.jp", "fujiidera.osaka.jp", "habikino.osaka.jp", "hannan.osaka.jp", "higashiosaka.osaka.jp", "higashisumiyoshi.osaka.jp", "higashiyodogawa.osaka.jp", "hirakata.osaka.jp", "ibaraki.osaka.jp", "ikeda.osaka.jp", "izumi.osaka.jp", "izumiotsu.osaka.jp", "izumisano.osaka.jp", "kadoma.osaka.jp", "kaizuka.osaka.jp", "kanan.osaka.jp", "kashiwara.osaka.jp", "katano.osaka.jp", "kawachinagano.osaka.jp", "kishiwada.osaka.jp", "kita.osaka.jp", "kumatori.osaka.jp", "matsubara.osaka.jp", "minato.osaka.jp", "minoh.osaka.jp", "misaki.osaka.jp", "moriguchi.osaka.jp", "neyagawa.osaka.jp", "nishi.osaka.jp", "nose.osaka.jp", "osakasayama.osaka.jp", "sakai.osaka.jp", "sayama.osaka.jp", "sennan.osaka.jp", "settsu.osaka.jp", "shijonawate.osaka.jp", "shimamoto.osaka.jp", "suita.osaka.jp", "tadaoka.osaka.jp", "taishi.osaka.jp", "tajiri.osaka.jp", "takaishi.osaka.jp", "takatsuki.osaka.jp", "tondabayashi.osaka.jp", "toyonaka.osaka.jp", "toyono.osaka.jp", "yao.osaka.jp", "ariake.saga.jp", "arita.saga.jp", "fukudomi.saga.jp", "genkai.saga.jp", "hamatama.saga.jp", "hizen.saga.jp", "imari.saga.jp", "kamimine.saga.jp", "kanzaki.saga.jp", "karatsu.saga.jp", "kashima.saga.jp", "kitagata.saga.jp", "kitahata.saga.jp", "kiyama.saga.jp", "kouhoku.saga.jp", "kyuragi.saga.jp", "nishiarita.saga.jp", "ogi.saga.jp", "omachi.saga.jp", "ouchi.saga.jp", "saga.saga.jp", "shiroishi.saga.jp", "taku.saga.jp", "tara.saga.jp", "tosu.saga.jp", "yoshinogari.saga.jp", "arakawa.saitama.jp", "asaka.saitama.jp", "chichibu.saitama.jp", "fujimi.saitama.jp", "fujimino.saitama.jp", "fukaya.saitama.jp", "hanno.saitama.jp", "hanyu.saitama.jp", "hasuda.saitama.jp", "hatogaya.saitama.jp", "hatoyama.saitama.jp", "hidaka.saitama.jp", "higashichichibu.saitama.jp", "higashimatsuyama.saitama.jp", "honjo.saitama.jp", "ina.saitama.jp", "iruma.saitama.jp", "iwatsuki.saitama.jp", "kamiizumi.saitama.jp", "kamikawa.saitama.jp", "kamisato.saitama.jp", "kasukabe.saitama.jp", "kawagoe.saitama.jp", "kawaguchi.saitama.jp", "kawajima.saitama.jp", "kazo.saitama.jp", "kitamoto.saitama.jp", "koshigaya.saitama.jp", "kounosu.saitama.jp", "kuki.saitama.jp", "kumagaya.saitama.jp", "matsubushi.saitama.jp", "minano.saitama.jp", "misato.saitama.jp", "miyashiro.saitama.jp", "miyoshi.saitama.jp", "moroyama.saitama.jp", "nagatoro.saitama.jp", "namegawa.saitama.jp", "niiza.saitama.jp", "ogano.saitama.jp", "ogawa.saitama.jp", "ogose.saitama.jp", "okegawa.saitama.jp", "omiya.saitama.jp", "otaki.saitama.jp", "ranzan.saitama.jp", "ryokami.saitama.jp", "saitama.saitama.jp", "sakado.saitama.jp", "satte.saitama.jp", "sayama.saitama.jp", "shiki.saitama.jp", "shiraoka.saitama.jp", "soka.saitama.jp", "sugito.saitama.jp", "toda.saitama.jp", "tokigawa.saitama.jp", "tokorozawa.saitama.jp", "tsurugashima.saitama.jp", "urawa.saitama.jp", "warabi.saitama.jp", "yashio.saitama.jp", "yokoze.saitama.jp", "yono.saitama.jp", "yorii.saitama.jp", "yoshida.saitama.jp", "yoshikawa.saitama.jp", "yoshimi.saitama.jp", "aisho.shiga.jp", "gamo.shiga.jp", "higashiomi.shiga.jp", "hikone.shiga.jp", "koka.shiga.jp", "konan.shiga.jp", "kosei.shiga.jp", "koto.shiga.jp", "kusatsu.shiga.jp", "maibara.shiga.jp", "moriyama.shiga.jp", "nagahama.shiga.jp", "nishiazai.shiga.jp", "notogawa.shiga.jp", "omihachiman.shiga.jp", "otsu.shiga.jp", "ritto.shiga.jp", "ryuoh.shiga.jp", "takashima.shiga.jp", "takatsuki.shiga.jp", "torahime.shiga.jp", "toyosato.shiga.jp", "yasu.shiga.jp", "akagi.shimane.jp", "ama.shimane.jp", "gotsu.shimane.jp", "hamada.shimane.jp", "higashiizumo.shimane.jp", "hikawa.shimane.jp", "hikimi.shimane.jp", "izumo.shimane.jp", "kakinoki.shimane.jp", "masuda.shimane.jp", "matsue.shimane.jp", "misato.shimane.jp", "nishinoshima.shimane.jp", "ohda.shimane.jp", "okinoshima.shimane.jp", "okuizumo.shimane.jp", "shimane.shimane.jp", "tamayu.shimane.jp", "tsuwano.shimane.jp", "unnan.shimane.jp", "yakumo.shimane.jp", "yasugi.shimane.jp", "yatsuka.shimane.jp", "arai.shizuoka.jp", "atami.shizuoka.jp", "fuji.shizuoka.jp", "fujieda.shizuoka.jp", "fujikawa.shizuoka.jp", "fujinomiya.shizuoka.jp", "fukuroi.shizuoka.jp", "gotemba.shizuoka.jp", "haibara.shizuoka.jp", "hamamatsu.shizuoka.jp", "higashiizu.shizuoka.jp", "ito.shizuoka.jp", "iwata.shizuoka.jp", "izu.shizuoka.jp", "izunokuni.shizuoka.jp", "kakegawa.shizuoka.jp", "kannami.shizuoka.jp", "kawanehon.shizuoka.jp", "kawazu.shizuoka.jp", "kikugawa.shizuoka.jp", "kosai.shizuoka.jp", "makinohara.shizuoka.jp", "matsuzaki.shizuoka.jp", "minamiizu.shizuoka.jp", "mishima.shizuoka.jp", "morimachi.shizuoka.jp", "nishiizu.shizuoka.jp", "numazu.shizuoka.jp", "omaezaki.shizuoka.jp", "shimada.shizuoka.jp", "shimizu.shizuoka.jp", "shimoda.shizuoka.jp", "shizuoka.shizuoka.jp", "susono.shizuoka.jp", "yaizu.shizuoka.jp", "yoshida.shizuoka.jp", "ashikaga.tochigi.jp", "bato.tochigi.jp", "haga.tochigi.jp", "ichikai.tochigi.jp", "iwafune.tochigi.jp", "kaminokawa.tochigi.jp", "kanuma.tochigi.jp", "karasuyama.tochigi.jp", "kuroiso.tochigi.jp", "mashiko.tochigi.jp", "mibu.tochigi.jp", "moka.tochigi.jp", "motegi.tochigi.jp", "nasu.tochigi.jp", "nasushiobara.tochigi.jp", "nikko.tochigi.jp", "nishikata.tochigi.jp", "nogi.tochigi.jp", "ohira.tochigi.jp", "ohtawara.tochigi.jp", "oyama.tochigi.jp", "sakura.tochigi.jp", "sano.tochigi.jp", "shimotsuke.tochigi.jp", "shioya.tochigi.jp", "takanezawa.tochigi.jp", "tochigi.tochigi.jp", "tsuga.tochigi.jp", "ujiie.tochigi.jp", "utsunomiya.tochigi.jp", "yaita.tochigi.jp", "aizumi.tokushima.jp", "anan.tokushima.jp", "ichiba.tokushima.jp", "itano.tokushima.jp", "kainan.tokushima.jp", "komatsushima.tokushima.jp", "matsushige.tokushima.jp", "mima.tokushima.jp", "minami.tokushima.jp", "miyoshi.tokushima.jp", "mugi.tokushima.jp", "nakagawa.tokushima.jp", "naruto.tokushima.jp", "sanagochi.tokushima.jp", "shishikui.tokushima.jp", "tokushima.tokushima.jp", "wajiki.tokushima.jp", "adachi.tokyo.jp", "akiruno.tokyo.jp", "akishima.tokyo.jp", "aogashima.tokyo.jp", "arakawa.tokyo.jp", "bunkyo.tokyo.jp", "chiyoda.tokyo.jp", "chofu.tokyo.jp", "chuo.tokyo.jp", "edogawa.tokyo.jp", "fuchu.tokyo.jp", "fussa.tokyo.jp", "hachijo.tokyo.jp", "hachioji.tokyo.jp", "hamura.tokyo.jp", "higashikurume.tokyo.jp", "higashimurayama.tokyo.jp", "higashiyamato.tokyo.jp", "hino.tokyo.jp", "hinode.tokyo.jp", "hinohara.tokyo.jp", "inagi.tokyo.jp", "itabashi.tokyo.jp", "katsushika.tokyo.jp", "kita.tokyo.jp", "kiyose.tokyo.jp", "kodaira.tokyo.jp", "koganei.tokyo.jp", "kokubunji.tokyo.jp", "komae.tokyo.jp", "koto.tokyo.jp", "kouzushima.tokyo.jp", "kunitachi.tokyo.jp", "machida.tokyo.jp", "meguro.tokyo.jp", "minato.tokyo.jp", "mitaka.tokyo.jp", "mizuho.tokyo.jp", "musashimurayama.tokyo.jp", "musashino.tokyo.jp", "nakano.tokyo.jp", "nerima.tokyo.jp", "ogasawara.tokyo.jp", "okutama.tokyo.jp", "ome.tokyo.jp", "oshima.tokyo.jp", "ota.tokyo.jp", "setagaya.tokyo.jp", "shibuya.tokyo.jp", "shinagawa.tokyo.jp", "shinjuku.tokyo.jp", "suginami.tokyo.jp", "sumida.tokyo.jp", "tachikawa.tokyo.jp", "taito.tokyo.jp", "tama.tokyo.jp", "toshima.tokyo.jp", "chizu.tottori.jp", "hino.tottori.jp", "kawahara.tottori.jp", "koge.tottori.jp", "kotoura.tottori.jp", "misasa.tottori.jp", "nanbu.tottori.jp", "nichinan.tottori.jp", "sakaiminato.tottori.jp", "tottori.tottori.jp", "wakasa.tottori.jp", "yazu.tottori.jp", "yonago.tottori.jp", "asahi.toyama.jp", "fuchu.toyama.jp", "fukumitsu.toyama.jp", "funahashi.toyama.jp", "himi.toyama.jp", "imizu.toyama.jp", "inami.toyama.jp", "johana.toyama.jp", "kamiichi.toyama.jp", "kurobe.toyama.jp", "nakaniikawa.toyama.jp", "namerikawa.toyama.jp", "nanto.toyama.jp", "nyuzen.toyama.jp", "oyabe.toyama.jp", "taira.toyama.jp", "takaoka.toyama.jp", "tateyama.toyama.jp", "toga.toyama.jp", "tonami.toyama.jp", "toyama.toyama.jp", "unazuki.toyama.jp", "uozu.toyama.jp", "yamada.toyama.jp", "arida.wakayama.jp", "aridagawa.wakayama.jp", "gobo.wakayama.jp", "hashimoto.wakayama.jp", "hidaka.wakayama.jp", "hirogawa.wakayama.jp", "inami.wakayama.jp", "iwade.wakayama.jp", "kainan.wakayama.jp", "kamitonda.wakayama.jp", "katsuragi.wakayama.jp", "kimino.wakayama.jp", "kinokawa.wakayama.jp", "kitayama.wakayama.jp", "koya.wakayama.jp", "koza.wakayama.jp", "kozagawa.wakayama.jp", "kudoyama.wakayama.jp", "kushimoto.wakayama.jp", "mihama.wakayama.jp", "misato.wakayama.jp", "nachikatsuura.wakayama.jp", "shingu.wakayama.jp", "shirahama.wakayama.jp", "taiji.wakayama.jp", "tanabe.wakayama.jp", "wakayama.wakayama.jp", "yuasa.wakayama.jp", "yura.wakayama.jp", "asahi.yamagata.jp", "funagata.yamagata.jp", "higashine.yamagata.jp", "iide.yamagata.jp", "kahoku.yamagata.jp", "kaminoyama.yamagata.jp", "kaneyama.yamagata.jp", "kawanishi.yamagata.jp", "mamurogawa.yamagata.jp", "mikawa.yamagata.jp", "murayama.yamagata.jp", "nagai.yamagata.jp", "nakayama.yamagata.jp", "nanyo.yamagata.jp", "nishikawa.yamagata.jp", "obanazawa.yamagata.jp", "oe.yamagata.jp", "oguni.yamagata.jp", "ohkura.yamagata.jp", "oishida.yamagata.jp", "sagae.yamagata.jp", "sakata.yamagata.jp", "sakegawa.yamagata.jp", "shinjo.yamagata.jp", "shirataka.yamagata.jp", "shonai.yamagata.jp", "takahata.yamagata.jp", "tendo.yamagata.jp", "tozawa.yamagata.jp", "tsuruoka.yamagata.jp", "yamagata.yamagata.jp", "yamanobe.yamagata.jp", "yonezawa.yamagata.jp", "yuza.yamagata.jp", "abu.yamaguchi.jp", "hagi.yamaguchi.jp", "hikari.yamaguchi.jp", "hofu.yamaguchi.jp", "iwakuni.yamaguchi.jp", "kudamatsu.yamaguchi.jp", "mitou.yamaguchi.jp", "nagato.yamaguchi.jp", "oshima.yamaguchi.jp", "shimonoseki.yamaguchi.jp", "shunan.yamaguchi.jp", "tabuse.yamaguchi.jp", "tokuyama.yamaguchi.jp", "toyota.yamaguchi.jp", "ube.yamaguchi.jp", "yuu.yamaguchi.jp", "chuo.yamanashi.jp", "doshi.yamanashi.jp", "fuefuki.yamanashi.jp", "fujikawa.yamanashi.jp", "fujikawaguchiko.yamanashi.jp", "fujiyoshida.yamanashi.jp", "hayakawa.yamanashi.jp", "hokuto.yamanashi.jp", "ichikawamisato.yamanashi.jp", "kai.yamanashi.jp", "kofu.yamanashi.jp", "koshu.yamanashi.jp", "kosuge.yamanashi.jp", "minami-alps.yamanashi.jp", "minobu.yamanashi.jp", "nakamichi.yamanashi.jp", "nanbu.yamanashi.jp", "narusawa.yamanashi.jp", "nirasaki.yamanashi.jp", "nishikatsura.yamanashi.jp", "oshino.yamanashi.jp", "otsuki.yamanashi.jp", "showa.yamanashi.jp", "tabayama.yamanashi.jp", "tsuru.yamanashi.jp", "uenohara.yamanashi.jp", "yamanakako.yamanashi.jp", "yamanashi.yamanashi.jp", "*.ke", "kg", "org.kg", "net.kg", "com.kg", "edu.kg", "gov.kg", "mil.kg", "*.kh", "ki", "edu.ki", "biz.ki", "net.ki", "org.ki", "gov.ki", "info.ki", "com.ki", "km", "org.km", "nom.km", "gov.km", "prd.km", "tm.km", "edu.km", "mil.km", "ass.km", "com.km", "coop.km", "asso.km", "presse.km", "medecin.km", "notaires.km", "pharmaciens.km", "veterinaire.km", "gouv.km", "kn", "net.kn", "org.kn", "edu.kn", "gov.kn", "kp", "com.kp", "edu.kp", "gov.kp", "org.kp", "rep.kp", "tra.kp", "kr", "ac.kr", "co.kr", "es.kr", "go.kr", "hs.kr", "kg.kr", "mil.kr", "ms.kr", "ne.kr", "or.kr", "pe.kr", "re.kr", "sc.kr", "busan.kr", "chungbuk.kr", "chungnam.kr", "daegu.kr", "daejeon.kr", "gangwon.kr", "gwangju.kr", "gyeongbuk.kr", "gyeonggi.kr", "gyeongnam.kr", "incheon.kr", "jeju.kr", "jeonbuk.kr", "jeonnam.kr", "seoul.kr", "ulsan.kr", "*.kw", "ky", "edu.ky", "gov.ky", "com.ky", "org.ky", "net.ky", "kz", "org.kz", "edu.kz", "net.kz", "gov.kz", "mil.kz", "com.kz", "la", "int.la", "net.la", "info.la", "edu.la", "gov.la", "per.la", "com.la", "org.la", "lb", "com.lb", "edu.lb", "gov.lb", "net.lb", "org.lb", "lc", "com.lc", "net.lc", "co.lc", "org.lc", "edu.lc", "gov.lc", "li", "lk", "gov.lk", "sch.lk", "net.lk", "int.lk", "com.lk", "org.lk", "edu.lk", "ngo.lk", "soc.lk", "web.lk", "ltd.lk", "assn.lk", "grp.lk", "hotel.lk", "ac.lk", "lr", "com.lr", "edu.lr", "gov.lr", "org.lr", "net.lr", "ls", "co.ls", "org.ls", "lt", "gov.lt", "lu", "lv", "com.lv", "edu.lv", "gov.lv", "org.lv", "mil.lv", "id.lv", "net.lv", "asn.lv", "conf.lv", "ly", "com.ly", "net.ly", "gov.ly", "plc.ly", "edu.ly", "sch.ly", "med.ly", "org.ly", "id.ly", "ma", "co.ma", "net.ma", "gov.ma", "org.ma", "ac.ma", "press.ma", "mc", "tm.mc", "asso.mc", "md", "me", "co.me", "net.me", "org.me", "edu.me", "ac.me", "gov.me", "its.me", "priv.me", "mg", "org.mg", "nom.mg", "gov.mg", "prd.mg", "tm.mg", "edu.mg", "mil.mg", "com.mg", "co.mg", "mh", "mil", "mk", "com.mk", "org.mk", "net.mk", "edu.mk", "gov.mk", "inf.mk", "name.mk", "ml", "com.ml", "edu.ml", "gouv.ml", "gov.ml", "net.ml", "org.ml", "presse.ml", "*.mm", "mn", "gov.mn", "edu.mn", "org.mn", "mo", "com.mo", "net.mo", "org.mo", "edu.mo", "gov.mo", "mobi", "mp", "mq", "mr", "gov.mr", "ms", "com.ms", "edu.ms", "gov.ms", "net.ms", "org.ms", "mt", "com.mt", "edu.mt", "net.mt", "org.mt", "mu", "com.mu", "net.mu", "org.mu", "gov.mu", "ac.mu", "co.mu", "or.mu", "museum", "academy.museum", "agriculture.museum", "air.museum", "airguard.museum", "alabama.museum", "alaska.museum", "amber.museum", "ambulance.museum", "american.museum", "americana.museum", "americanantiques.museum", "americanart.museum", "amsterdam.museum", "and.museum", "annefrank.museum", "anthro.museum", "anthropology.museum", "antiques.museum", "aquarium.museum", "arboretum.museum", "archaeological.museum", "archaeology.museum", "architecture.museum", "art.museum", "artanddesign.museum", "artcenter.museum", "artdeco.museum", "arteducation.museum", "artgallery.museum", "arts.museum", "artsandcrafts.museum", "asmatart.museum", "assassination.museum", "assisi.museum", "association.museum", "astronomy.museum", "atlanta.museum", "austin.museum", "australia.museum", "automotive.museum", "aviation.museum", "axis.museum", "badajoz.museum", "baghdad.museum", "bahn.museum", "bale.museum", "baltimore.museum", "barcelona.museum", "baseball.museum", "basel.museum", "baths.museum", "bauern.museum", "beauxarts.museum", "beeldengeluid.museum", "bellevue.museum", "bergbau.museum", "berkeley.museum", "berlin.museum", "bern.museum", "bible.museum", "bilbao.museum", "bill.museum", "birdart.museum", "birthplace.museum", "bonn.museum", "boston.museum", "botanical.museum", "botanicalgarden.museum", "botanicgarden.museum", "botany.museum", "brandywinevalley.museum", "brasil.museum", "bristol.museum", "british.museum", "britishcolumbia.museum", "broadcast.museum", "brunel.museum", "brussel.museum", "brussels.museum", "bruxelles.museum", "building.museum", "burghof.museum", "bus.museum", "bushey.museum", "cadaques.museum", "california.museum", "cambridge.museum", "can.museum", "canada.museum", "capebreton.museum", "carrier.museum", "cartoonart.museum", "casadelamoneda.museum", "castle.museum", "castres.museum", "celtic.museum", "center.museum", "chattanooga.museum", "cheltenham.museum", "chesapeakebay.museum", "chicago.museum", "children.museum", "childrens.museum", "childrensgarden.museum", "chiropractic.museum", "chocolate.museum", "christiansburg.museum", "cincinnati.museum", "cinema.museum", "circus.museum", "civilisation.museum", "civilization.museum", "civilwar.museum", "clinton.museum", "clock.museum", "coal.museum", "coastaldefence.museum", "cody.museum", "coldwar.museum", "collection.museum", "colonialwilliamsburg.museum", "coloradoplateau.museum", "columbia.museum", "columbus.museum", "communication.museum", "communications.museum", "community.museum", "computer.museum", "computerhistory.museum", "xn--comunicaes-v6a2o.museum", "contemporary.museum", "contemporaryart.museum", "convent.museum", "copenhagen.museum", "corporation.museum", "xn--correios-e-telecomunicaes-ghc29a.museum", "corvette.museum", "costume.museum", "countryestate.museum", "county.museum", "crafts.museum", "cranbrook.museum", "creation.museum", "cultural.museum", "culturalcenter.museum", "culture.museum", "cyber.museum", "cymru.museum", "dali.museum", "dallas.museum", "database.museum", "ddr.museum", "decorativearts.museum", "delaware.museum", "delmenhorst.museum", "denmark.museum", "depot.museum", "design.museum", "detroit.museum", "dinosaur.museum", "discovery.museum", "dolls.museum", "donostia.museum", "durham.museum", "eastafrica.museum", "eastcoast.museum", "education.museum", "educational.museum", "egyptian.museum", "eisenbahn.museum", "elburg.museum", "elvendrell.museum", "embroidery.museum", "encyclopedic.museum", "england.museum", "entomology.museum", "environment.museum", "environmentalconservation.museum", "epilepsy.museum", "essex.museum", "estate.museum", "ethnology.museum", "exeter.museum", "exhibition.museum", "family.museum", "farm.museum", "farmequipment.museum", "farmers.museum", "farmstead.museum", "field.museum", "figueres.museum", "filatelia.museum", "film.museum", "fineart.museum", "finearts.museum", "finland.museum", "flanders.museum", "florida.museum", "force.museum", "fortmissoula.museum", "fortworth.museum", "foundation.museum", "francaise.museum", "frankfurt.museum", "franziskaner.museum", "freemasonry.museum", "freiburg.museum", "fribourg.museum", "frog.museum", "fundacio.museum", "furniture.museum", "gallery.museum", "garden.museum", "gateway.museum", "geelvinck.museum", "gemological.museum", "geology.museum", "georgia.museum", "giessen.museum", "glas.museum", "glass.museum", "gorge.museum", "grandrapids.museum", "graz.museum", "guernsey.museum", "halloffame.museum", "hamburg.museum", "handson.museum", "harvestcelebration.museum", "hawaii.museum", "health.museum", "heimatunduhren.museum", "hellas.museum", "helsinki.museum", "hembygdsforbund.museum", "heritage.museum", "histoire.museum", "historical.museum", "historicalsociety.museum", "historichouses.museum", "historisch.museum", "historisches.museum", "history.museum", "historyofscience.museum", "horology.museum", "house.museum", "humanities.museum", "illustration.museum", "imageandsound.museum", "indian.museum", "indiana.museum", "indianapolis.museum", "indianmarket.museum", "intelligence.museum", "interactive.museum", "iraq.museum", "iron.museum", "isleofman.museum", "jamison.museum", "jefferson.museum", "jerusalem.museum", "jewelry.museum", "jewish.museum", "jewishart.museum", "jfk.museum", "journalism.museum", "judaica.museum", "judygarland.museum", "juedisches.museum", "juif.museum", "karate.museum", "karikatur.museum", "kids.museum", "koebenhavn.museum", "koeln.museum", "kunst.museum", "kunstsammlung.museum", "kunstunddesign.museum", "labor.museum", "labour.museum", "lajolla.museum", "lancashire.museum", "landes.museum", "lans.museum", "xn--lns-qla.museum", "larsson.museum", "lewismiller.museum", "lincoln.museum", "linz.museum", "living.museum", "livinghistory.museum", "localhistory.museum", "london.museum", "losangeles.museum", "louvre.museum", "loyalist.museum", "lucerne.museum", "luxembourg.museum", "luzern.museum", "mad.museum", "madrid.museum", "mallorca.museum", "manchester.museum", "mansion.museum", "mansions.museum", "manx.museum", "marburg.museum", "maritime.museum", "maritimo.museum", "maryland.museum", "marylhurst.museum", "media.museum", "medical.museum", "medizinhistorisches.museum", "meeres.museum", "memorial.museum", "mesaverde.museum", "michigan.museum", "midatlantic.museum", "military.museum", "mill.museum", "miners.museum", "mining.museum", "minnesota.museum", "missile.museum", "missoula.museum", "modern.museum", "moma.museum", "money.museum", "monmouth.museum", "monticello.museum", "montreal.museum", "moscow.museum", "motorcycle.museum", "muenchen.museum", "muenster.museum", "mulhouse.museum", "muncie.museum", "museet.museum", "museumcenter.museum", "museumvereniging.museum", "music.museum", "national.museum", "nationalfirearms.museum", "nationalheritage.museum", "nativeamerican.museum", "naturalhistory.museum", "naturalhistorymuseum.museum", "naturalsciences.museum", "nature.museum", "naturhistorisches.museum", "natuurwetenschappen.museum", "naumburg.museum", "naval.museum", "nebraska.museum", "neues.museum", "newhampshire.museum", "newjersey.museum", "newmexico.museum", "newport.museum", "newspaper.museum", "newyork.museum", "niepce.museum", "norfolk.museum", "north.museum", "nrw.museum", "nuernberg.museum", "nuremberg.museum", "nyc.museum", "nyny.museum", "oceanographic.museum", "oceanographique.museum", "omaha.museum", "online.museum", "ontario.museum", "openair.museum", "oregon.museum", "oregontrail.museum", "otago.museum", "oxford.museum", "pacific.museum", "paderborn.museum", "palace.museum", "paleo.museum", "palmsprings.museum", "panama.museum", "paris.museum", "pasadena.museum", "pharmacy.museum", "philadelphia.museum", "philadelphiaarea.museum", "philately.museum", "phoenix.museum", "photography.museum", "pilots.museum", "pittsburgh.museum", "planetarium.museum", "plantation.museum", "plants.museum", "plaza.museum", "portal.museum", "portland.museum", "portlligat.museum", "posts-and-telecommunications.museum", "preservation.museum", "presidio.museum", "press.museum", "project.museum", "public.museum", "pubol.museum", "quebec.museum", "railroad.museum", "railway.museum", "research.museum", "resistance.museum", "riodejaneiro.museum", "rochester.museum", "rockart.museum", "roma.museum", "russia.museum", "saintlouis.museum", "salem.museum", "salvadordali.museum", "salzburg.museum", "sandiego.museum", "sanfrancisco.museum", "santabarbara.museum", "santacruz.museum", "santafe.museum", "saskatchewan.museum", "satx.museum", "savannahga.museum", "schlesisches.museum", "schoenbrunn.museum", "schokoladen.museum", "school.museum", "schweiz.museum", "science.museum", "scienceandhistory.museum", "scienceandindustry.museum", "sciencecenter.museum", "sciencecenters.museum", "science-fiction.museum", "sciencehistory.museum", "sciences.museum", "sciencesnaturelles.museum", "scotland.museum", "seaport.museum", "settlement.museum", "settlers.museum", "shell.museum", "sherbrooke.museum", "sibenik.museum", "silk.museum", "ski.museum", "skole.museum", "society.museum", "sologne.museum", "soundandvision.museum", "southcarolina.museum", "southwest.museum", "space.museum", "spy.museum", "square.museum", "stadt.museum", "stalbans.museum", "starnberg.museum", "state.museum", "stateofdelaware.museum", "station.museum", "steam.museum", "steiermark.museum", "stjohn.museum", "stockholm.museum", "stpetersburg.museum", "stuttgart.museum", "suisse.museum", "surgeonshall.museum", "surrey.museum", "svizzera.museum", "sweden.museum", "sydney.museum", "tank.museum", "tcm.museum", "technology.museum", "telekommunikation.museum", "television.museum", "texas.museum", "textile.museum", "theater.museum", "time.museum", "timekeeping.museum", "topology.museum", "torino.museum", "touch.museum", "town.museum", "transport.museum", "tree.museum", "trolley.museum", "trust.museum", "trustee.museum", "uhren.museum", "ulm.museum", "undersea.museum", "university.museum", "usa.museum", "usantiques.museum", "usarts.museum", "uscountryestate.museum", "usculture.museum", "usdecorativearts.museum", "usgarden.museum", "ushistory.museum", "ushuaia.museum", "uslivinghistory.museum", "utah.museum", "uvic.museum", "valley.museum", "vantaa.museum", "versailles.museum", "viking.museum", "village.museum", "virginia.museum", "virtual.museum", "virtuel.museum", "vlaanderen.museum", "volkenkunde.museum", "wales.museum", "wallonie.museum", "war.museum", "washingtondc.museum", "watchandclock.museum", "watch-and-clock.museum", "western.museum", "westfalen.museum", "whaling.museum", "wildlife.museum", "williamsburg.museum", "windmill.museum", "workshop.museum", "york.museum", "yorkshire.museum", "yosemite.museum", "youth.museum", "zoological.museum", "zoology.museum", "xn--9dbhblg6di.museum", "xn--h1aegh.museum", "mv", "aero.mv", "biz.mv", "com.mv", "coop.mv", "edu.mv", "gov.mv", "info.mv", "int.mv", "mil.mv", "museum.mv", "name.mv", "net.mv", "org.mv", "pro.mv", "mw", "ac.mw", "biz.mw", "co.mw", "com.mw", "coop.mw", "edu.mw", "gov.mw", "int.mw", "museum.mw", "net.mw", "org.mw", "mx", "com.mx", "org.mx", "gob.mx", "edu.mx", "net.mx", "my", "com.my", "net.my", "org.my", "gov.my", "edu.my", "mil.my", "name.my", "*.mz", "!teledata.mz", "na", "info.na", "pro.na", "name.na", "school.na", "or.na", "dr.na", "us.na", "mx.na", "ca.na", "in.na", "cc.na", "tv.na", "ws.na", "mobi.na", "co.na", "com.na", "org.na", "name", "nc", "asso.nc", "ne", "net", "nf", "com.nf", "net.nf", "per.nf", "rec.nf", "web.nf", "arts.nf", "firm.nf", "info.nf", "other.nf", "store.nf", "ng", "com.ng", "edu.ng", "name.ng", "net.ng", "org.ng", "sch.ng", "gov.ng", "mil.ng", "mobi.ng", "com.ni", "gob.ni", "edu.ni", "org.ni", "nom.ni", "net.ni", "mil.ni", "co.ni", "biz.ni", "web.ni", "int.ni", "ac.ni", "in.ni", "info.ni", "nl", "bv.nl", "no", "fhs.no", "vgs.no", "fylkesbibl.no", "folkebibl.no", "museum.no", "idrett.no", "priv.no", "mil.no", "stat.no", "dep.no", "kommune.no", "herad.no", "aa.no", "ah.no", "bu.no", "fm.no", "hl.no", "hm.no", "jan-mayen.no", "mr.no", "nl.no", "nt.no", "of.no", "ol.no", "oslo.no", "rl.no", "sf.no", "st.no", "svalbard.no", "tm.no", "tr.no", "va.no", "vf.no", "gs.aa.no", "gs.ah.no", "gs.bu.no", "gs.fm.no", "gs.hl.no", "gs.hm.no", "gs.jan-mayen.no", "gs.mr.no", "gs.nl.no", "gs.nt.no", "gs.of.no", "gs.ol.no", "gs.oslo.no", "gs.rl.no", "gs.sf.no", "gs.st.no", "gs.svalbard.no", "gs.tm.no", "gs.tr.no", "gs.va.no", "gs.vf.no", "akrehamn.no", "xn--krehamn-dxa.no", "algard.no", "xn--lgrd-poac.no", "arna.no", "brumunddal.no", "bryne.no", "bronnoysund.no", "xn--brnnysund-m8ac.no", "drobak.no", "xn--drbak-wua.no", "egersund.no", "fetsund.no", "floro.no", "xn--flor-jra.no", "fredrikstad.no", "hokksund.no", "honefoss.no", "xn--hnefoss-q1a.no", "jessheim.no", "jorpeland.no", "xn--jrpeland-54a.no", "kirkenes.no", "kopervik.no", "krokstadelva.no", "langevag.no", "xn--langevg-jxa.no", "leirvik.no", "mjondalen.no", "xn--mjndalen-64a.no", "mo-i-rana.no", "mosjoen.no", "xn--mosjen-eya.no", "nesoddtangen.no", "orkanger.no", "osoyro.no", "xn--osyro-wua.no", "raholt.no", "xn--rholt-mra.no", "sandnessjoen.no", "xn--sandnessjen-ogb.no", "skedsmokorset.no", "slattum.no", "spjelkavik.no", "stathelle.no", "stavern.no", "stjordalshalsen.no", "xn--stjrdalshalsen-sqb.no", "tananger.no", "tranby.no", "vossevangen.no", "afjord.no", "xn--fjord-lra.no", "agdenes.no", "al.no", "xn--l-1fa.no", "alesund.no", "xn--lesund-hua.no", "alstahaug.no", "alta.no", "xn--lt-liac.no", "alaheadju.no", "xn--laheadju-7ya.no", "alvdal.no", "amli.no", "xn--mli-tla.no", "amot.no", "xn--mot-tla.no", "andebu.no", "andoy.no", "xn--andy-ira.no", "andasuolo.no", "ardal.no", "xn--rdal-poa.no", "aremark.no", "arendal.no", "xn--s-1fa.no", "aseral.no", "xn--seral-lra.no", "asker.no", "askim.no", "askvoll.no", "askoy.no", "xn--asky-ira.no", "asnes.no", "xn--snes-poa.no", "audnedaln.no", "aukra.no", "aure.no", "aurland.no", "aurskog-holand.no", "xn--aurskog-hland-jnb.no", "austevoll.no", "austrheim.no", "averoy.no", "xn--avery-yua.no", "balestrand.no", "ballangen.no", "balat.no", "xn--blt-elab.no", "balsfjord.no", "bahccavuotna.no", "xn--bhccavuotna-k7a.no", "bamble.no", "bardu.no", "beardu.no", "beiarn.no", "bajddar.no", "xn--bjddar-pta.no", "baidar.no", "xn--bidr-5nac.no", "berg.no", "bergen.no", "berlevag.no", "xn--berlevg-jxa.no", "bearalvahki.no", "xn--bearalvhki-y4a.no", "bindal.no", "birkenes.no", "bjarkoy.no", "xn--bjarky-fya.no", "bjerkreim.no", "bjugn.no", "bodo.no", "xn--bod-2na.no", "badaddja.no", "xn--bdddj-mrabd.no", "budejju.no", "bokn.no", "bremanger.no", "bronnoy.no", "xn--brnny-wuac.no", "bygland.no", "bykle.no", "barum.no", "xn--brum-voa.no", "bo.telemark.no", "xn--b-5ga.telemark.no", "bo.nordland.no", "xn--b-5ga.nordland.no", "bievat.no", "xn--bievt-0qa.no", "bomlo.no", "xn--bmlo-gra.no", "batsfjord.no", "xn--btsfjord-9za.no", "bahcavuotna.no", "xn--bhcavuotna-s4a.no", "dovre.no", "drammen.no", "drangedal.no", "dyroy.no", "xn--dyry-ira.no", "donna.no", "xn--dnna-gra.no", "eid.no", "eidfjord.no", "eidsberg.no", "eidskog.no", "eidsvoll.no", "eigersund.no", "elverum.no", "enebakk.no", "engerdal.no", "etne.no", "etnedal.no", "evenes.no", "evenassi.no", "xn--eveni-0qa01ga.no", "evje-og-hornnes.no", "farsund.no", "fauske.no", "fuossko.no", "fuoisku.no", "fedje.no", "fet.no", "finnoy.no", "xn--finny-yua.no", "fitjar.no", "fjaler.no", "fjell.no", "flakstad.no", "flatanger.no", "flekkefjord.no", "flesberg.no", "flora.no", "fla.no", "xn--fl-zia.no", "folldal.no", "forsand.no", "fosnes.no", "frei.no", "frogn.no", "froland.no", "frosta.no", "frana.no", "xn--frna-woa.no", "froya.no", "xn--frya-hra.no", "fusa.no", "fyresdal.no", "forde.no", "xn--frde-gra.no", "gamvik.no", "gangaviika.no", "xn--ggaviika-8ya47h.no", "gaular.no", "gausdal.no", "gildeskal.no", "xn--gildeskl-g0a.no", "giske.no", "gjemnes.no", "gjerdrum.no", "gjerstad.no", "gjesdal.no", "gjovik.no", "xn--gjvik-wua.no", "gloppen.no", "gol.no", "gran.no", "grane.no", "granvin.no", "gratangen.no", "grimstad.no", "grong.no", "kraanghke.no", "xn--kranghke-b0a.no", "grue.no", "gulen.no", "hadsel.no", "halden.no", "halsa.no", "hamar.no", "hamaroy.no", "habmer.no", "xn--hbmer-xqa.no", "hapmir.no", "xn--hpmir-xqa.no", "hammerfest.no", "hammarfeasta.no", "xn--hmmrfeasta-s4ac.no", "haram.no", "hareid.no", "harstad.no", "hasvik.no", "aknoluokta.no", "xn--koluokta-7ya57h.no", "hattfjelldal.no", "aarborte.no", "haugesund.no", "hemne.no", "hemnes.no", "hemsedal.no", "heroy.more-og-romsdal.no", "xn--hery-ira.xn--mre-og-romsdal-qqb.no", "heroy.nordland.no", "xn--hery-ira.nordland.no", "hitra.no", "hjartdal.no", "hjelmeland.no", "hobol.no", "xn--hobl-ira.no", "hof.no", "hol.no", "hole.no", "holmestrand.no", "holtalen.no", "xn--holtlen-hxa.no", "hornindal.no", "horten.no", "hurdal.no", "hurum.no", "hvaler.no", "hyllestad.no", "hagebostad.no", "xn--hgebostad-g3a.no", "hoyanger.no", "xn--hyanger-q1a.no", "hoylandet.no", "xn--hylandet-54a.no", "ha.no", "xn--h-2fa.no", "ibestad.no", "inderoy.no", "xn--indery-fya.no", "iveland.no", "jevnaker.no", "jondal.no", "jolster.no", "xn--jlster-bya.no", "karasjok.no", "karasjohka.no", "xn--krjohka-hwab49j.no", "karlsoy.no", "galsa.no", "xn--gls-elac.no", "karmoy.no", "xn--karmy-yua.no", "kautokeino.no", "guovdageaidnu.no", "klepp.no", "klabu.no", "xn--klbu-woa.no", "kongsberg.no", "kongsvinger.no", "kragero.no", "xn--krager-gya.no", "kristiansand.no", "kristiansund.no", "krodsherad.no", "xn--krdsherad-m8a.no", "kvalsund.no", "rahkkeravju.no", "xn--rhkkervju-01af.no", "kvam.no", "kvinesdal.no", "kvinnherad.no", "kviteseid.no", "kvitsoy.no", "xn--kvitsy-fya.no", "kvafjord.no", "xn--kvfjord-nxa.no", "giehtavuoatna.no", "kvanangen.no", "xn--kvnangen-k0a.no", "navuotna.no", "xn--nvuotna-hwa.no", "kafjord.no", "xn--kfjord-iua.no", "gaivuotna.no", "xn--givuotna-8ya.no", "larvik.no", "lavangen.no", "lavagis.no", "loabat.no", "xn--loabt-0qa.no", "lebesby.no", "davvesiida.no", "leikanger.no", "leirfjord.no", "leka.no", "leksvik.no", "lenvik.no", "leangaviika.no", "xn--leagaviika-52b.no", "lesja.no", "levanger.no", "lier.no", "lierne.no", "lillehammer.no", "lillesand.no", "lindesnes.no", "lindas.no", "xn--linds-pra.no", "lom.no", "loppa.no", "lahppi.no", "xn--lhppi-xqa.no", "lund.no", "lunner.no", "luroy.no", "xn--lury-ira.no", "luster.no", "lyngdal.no", "lyngen.no", "ivgu.no", "lardal.no", "lerdal.no", "xn--lrdal-sra.no", "lodingen.no", "xn--ldingen-q1a.no", "lorenskog.no", "xn--lrenskog-54a.no", "loten.no", "xn--lten-gra.no", "malvik.no", "masoy.no", "xn--msy-ula0h.no", "muosat.no", "xn--muost-0qa.no", "mandal.no", "marker.no", "marnardal.no", "masfjorden.no", "meland.no", "meldal.no", "melhus.no", "meloy.no", "xn--mely-ira.no", "meraker.no", "xn--merker-kua.no", "moareke.no", "xn--moreke-jua.no", "midsund.no", "midtre-gauldal.no", "modalen.no", "modum.no", "molde.no", "moskenes.no", "moss.no", "mosvik.no", "malselv.no", "xn--mlselv-iua.no", "malatvuopmi.no", "xn--mlatvuopmi-s4a.no", "namdalseid.no", "aejrie.no", "namsos.no", "namsskogan.no", "naamesjevuemie.no", "xn--nmesjevuemie-tcba.no", "laakesvuemie.no", "nannestad.no", "narvik.no", "narviika.no", "naustdal.no", "nedre-eiker.no", "nes.akershus.no", "nes.buskerud.no", "nesna.no", "nesodden.no", "nesseby.no", "unjarga.no", "xn--unjrga-rta.no", "nesset.no", "nissedal.no", "nittedal.no", "nord-aurdal.no", "nord-fron.no", "nord-odal.no", "norddal.no", "nordkapp.no", "davvenjarga.no", "xn--davvenjrga-y4a.no", "nordre-land.no", "nordreisa.no", "raisa.no", "xn--risa-5na.no", "nore-og-uvdal.no", "notodden.no", "naroy.no", "xn--nry-yla5g.no", "notteroy.no", "xn--nttery-byae.no", "odda.no", "oksnes.no", "xn--ksnes-uua.no", "oppdal.no", "oppegard.no", "xn--oppegrd-ixa.no", "orkdal.no", "orland.no", "xn--rland-uua.no", "orskog.no", "xn--rskog-uua.no", "orsta.no", "xn--rsta-fra.no", "os.hedmark.no", "os.hordaland.no", "osen.no", "osteroy.no", "xn--ostery-fya.no", "ostre-toten.no", "xn--stre-toten-zcb.no", "overhalla.no", "ovre-eiker.no", "xn--vre-eiker-k8a.no", "oyer.no", "xn--yer-zna.no", "oygarden.no", "xn--ygarden-p1a.no", "oystre-slidre.no", "xn--ystre-slidre-ujb.no", "porsanger.no", "porsangu.no", "xn--porsgu-sta26f.no", "porsgrunn.no", "radoy.no", "xn--rady-ira.no", "rakkestad.no", "rana.no", "ruovat.no", "randaberg.no", "rauma.no", "rendalen.no", "rennebu.no", "rennesoy.no", "xn--rennesy-v1a.no", "rindal.no", "ringebu.no", "ringerike.no", "ringsaker.no", "rissa.no", "risor.no", "xn--risr-ira.no", "roan.no", "rollag.no", "rygge.no", "ralingen.no", "xn--rlingen-mxa.no", "rodoy.no", "xn--rdy-0nab.no", "romskog.no", "xn--rmskog-bya.no", "roros.no", "xn--rros-gra.no", "rost.no", "xn--rst-0na.no", "royken.no", "xn--ryken-vua.no", "royrvik.no", "xn--ryrvik-bya.no", "rade.no", "xn--rde-ula.no", "salangen.no", "siellak.no", "saltdal.no", "salat.no", "xn--slt-elab.no", "xn--slat-5na.no", "samnanger.no", "sande.more-og-romsdal.no", "sande.xn--mre-og-romsdal-qqb.no", "sande.vestfold.no", "sandefjord.no", "sandnes.no", "sandoy.no", "xn--sandy-yua.no", "sarpsborg.no", "sauda.no", "sauherad.no", "sel.no", "selbu.no", "selje.no", "seljord.no", "sigdal.no", "siljan.no", "sirdal.no", "skaun.no", "skedsmo.no", "ski.no", "skien.no", "skiptvet.no", "skjervoy.no", "xn--skjervy-v1a.no", "skierva.no", "xn--skierv-uta.no", "skjak.no", "xn--skjk-soa.no", "skodje.no", "skanland.no", "xn--sknland-fxa.no", "skanit.no", "xn--sknit-yqa.no", "smola.no", "xn--smla-hra.no", "snillfjord.no", "snasa.no", "xn--snsa-roa.no", "snoasa.no", "snaase.no", "xn--snase-nra.no", "sogndal.no", "sokndal.no", "sola.no", "solund.no", "songdalen.no", "sortland.no", "spydeberg.no", "stange.no", "stavanger.no", "steigen.no", "steinkjer.no", "stjordal.no", "xn--stjrdal-s1a.no", "stokke.no", "stor-elvdal.no", "stord.no", "stordal.no", "storfjord.no", "omasvuotna.no", "strand.no", "stranda.no", "stryn.no", "sula.no", "suldal.no", "sund.no", "sunndal.no", "surnadal.no", "sveio.no", "svelvik.no", "sykkylven.no", "sogne.no", "xn--sgne-gra.no", "somna.no", "xn--smna-gra.no", "sondre-land.no", "xn--sndre-land-0cb.no", "sor-aurdal.no", "xn--sr-aurdal-l8a.no", "sor-fron.no", "xn--sr-fron-q1a.no", "sor-odal.no", "xn--sr-odal-q1a.no", "sor-varanger.no", "xn--sr-varanger-ggb.no", "matta-varjjat.no", "xn--mtta-vrjjat-k7af.no", "sorfold.no", "xn--srfold-bya.no", "sorreisa.no", "xn--srreisa-q1a.no", "sorum.no", "xn--srum-gra.no", "tana.no", "deatnu.no", "time.no", "tingvoll.no", "tinn.no", "tjeldsund.no", "dielddanuorri.no", "tjome.no", "xn--tjme-hra.no", "tokke.no", "tolga.no", "torsken.no", "tranoy.no", "xn--trany-yua.no", "tromso.no", "xn--troms-zua.no", "tromsa.no", "romsa.no", "trondheim.no", "troandin.no", "trysil.no", "trana.no", "xn--trna-woa.no", "trogstad.no", "xn--trgstad-r1a.no", "tvedestrand.no", "tydal.no", "tynset.no", "tysfjord.no", "divtasvuodna.no", "divttasvuotna.no", "tysnes.no", "tysvar.no", "xn--tysvr-vra.no", "tonsberg.no", "xn--tnsberg-q1a.no", "ullensaker.no", "ullensvang.no", "ulvik.no", "utsira.no", "vadso.no", "xn--vads-jra.no", "cahcesuolo.no", "xn--hcesuolo-7ya35b.no", "vaksdal.no", "valle.no", "vang.no", "vanylven.no", "vardo.no", "xn--vard-jra.no", "varggat.no", "xn--vrggt-xqad.no", "vefsn.no", "vaapste.no", "vega.no", "vegarshei.no", "xn--vegrshei-c0a.no", "vennesla.no", "verdal.no", "verran.no", "vestby.no", "vestnes.no", "vestre-slidre.no", "vestre-toten.no", "vestvagoy.no", "xn--vestvgy-ixa6o.no", "vevelstad.no", "vik.no", "vikna.no", "vindafjord.no", "volda.no", "voss.no", "varoy.no", "xn--vry-yla5g.no", "vagan.no", "xn--vgan-qoa.no", "voagat.no", "vagsoy.no", "xn--vgsy-qoa0j.no", "vaga.no", "xn--vg-yiab.no", "valer.ostfold.no", "xn--vler-qoa.xn--stfold-9xa.no", "valer.hedmark.no", "xn--vler-qoa.hedmark.no", "*.np", "nr", "biz.nr", "info.nr", "gov.nr", "edu.nr", "org.nr", "net.nr", "com.nr", "nu", "nz", "ac.nz", "co.nz", "cri.nz", "geek.nz", "gen.nz", "govt.nz", "health.nz", "iwi.nz", "kiwi.nz", "maori.nz", "mil.nz", "xn--mori-qsa.nz", "net.nz", "org.nz", "parliament.nz", "school.nz", "om", "co.om", "com.om", "edu.om", "gov.om", "med.om", "museum.om", "net.om", "org.om", "pro.om", "org", "pa", "ac.pa", "gob.pa", "com.pa", "org.pa", "sld.pa", "edu.pa", "net.pa", "ing.pa", "abo.pa", "med.pa", "nom.pa", "pe", "edu.pe", "gob.pe", "nom.pe", "mil.pe", "org.pe", "com.pe", "net.pe", "pf", "com.pf", "org.pf", "edu.pf", "*.pg", "ph", "com.ph", "net.ph", "org.ph", "gov.ph", "edu.ph", "ngo.ph", "mil.ph", "i.ph", "pk", "com.pk", "net.pk", "edu.pk", "org.pk", "fam.pk", "biz.pk", "web.pk", "gov.pk", "gob.pk", "gok.pk", "gon.pk", "gop.pk", "gos.pk", "info.pk", "pl", "com.pl", "net.pl", "org.pl", "aid.pl", "agro.pl", "atm.pl", "auto.pl", "biz.pl", "edu.pl", "gmina.pl", "gsm.pl", "info.pl", "mail.pl", "miasta.pl", "media.pl", "mil.pl", "nieruchomosci.pl", "nom.pl", "pc.pl", "powiat.pl", "priv.pl", "realestate.pl", "rel.pl", "sex.pl", "shop.pl", "sklep.pl", "sos.pl", "szkola.pl", "targi.pl", "tm.pl", "tourism.pl", "travel.pl", "turystyka.pl", "gov.pl", "ap.gov.pl", "ic.gov.pl", "is.gov.pl", "us.gov.pl", "kmpsp.gov.pl", "kppsp.gov.pl", "kwpsp.gov.pl", "psp.gov.pl", "wskr.gov.pl", "kwp.gov.pl", "mw.gov.pl", "ug.gov.pl", "um.gov.pl", "umig.gov.pl", "ugim.gov.pl", "upow.gov.pl", "uw.gov.pl", "starostwo.gov.pl", "pa.gov.pl", "po.gov.pl", "psse.gov.pl", "pup.gov.pl", "rzgw.gov.pl", "sa.gov.pl", "so.gov.pl", "sr.gov.pl", "wsa.gov.pl", "sko.gov.pl", "uzs.gov.pl", "wiih.gov.pl", "winb.gov.pl", "pinb.gov.pl", "wios.gov.pl", "witd.gov.pl", "wzmiuw.gov.pl", "piw.gov.pl", "wiw.gov.pl", "griw.gov.pl", "wif.gov.pl", "oum.gov.pl", "sdn.gov.pl", "zp.gov.pl", "uppo.gov.pl", "mup.gov.pl", "wuoz.gov.pl", "konsulat.gov.pl", "oirm.gov.pl", "augustow.pl", "babia-gora.pl", "bedzin.pl", "beskidy.pl", "bialowieza.pl", "bialystok.pl", "bielawa.pl", "bieszczady.pl", "boleslawiec.pl", "bydgoszcz.pl", "bytom.pl", "cieszyn.pl", "czeladz.pl", "czest.pl", "dlugoleka.pl", "elblag.pl", "elk.pl", "glogow.pl", "gniezno.pl", "gorlice.pl", "grajewo.pl", "ilawa.pl", "jaworzno.pl", "jelenia-gora.pl", "jgora.pl", "kalisz.pl", "kazimierz-dolny.pl", "karpacz.pl", "kartuzy.pl", "kaszuby.pl", "katowice.pl", "kepno.pl", "ketrzyn.pl", "klodzko.pl", "kobierzyce.pl", "kolobrzeg.pl", "konin.pl", "konskowola.pl", "kutno.pl", "lapy.pl", "lebork.pl", "legnica.pl", "lezajsk.pl", "limanowa.pl", "lomza.pl", "lowicz.pl", "lubin.pl", "lukow.pl", "malbork.pl", "malopolska.pl", "mazowsze.pl", "mazury.pl", "mielec.pl", "mielno.pl", "mragowo.pl", "naklo.pl", "nowaruda.pl", "nysa.pl", "olawa.pl", "olecko.pl", "olkusz.pl", "olsztyn.pl", "opoczno.pl", "opole.pl", "ostroda.pl", "ostroleka.pl", "ostrowiec.pl", "ostrowwlkp.pl", "pila.pl", "pisz.pl", "podhale.pl", "podlasie.pl", "polkowice.pl", "pomorze.pl", "pomorskie.pl", "prochowice.pl", "pruszkow.pl", "przeworsk.pl", "pulawy.pl", "radom.pl", "rawa-maz.pl", "rybnik.pl", "rzeszow.pl", "sanok.pl", "sejny.pl", "slask.pl", "slupsk.pl", "sosnowiec.pl", "stalowa-wola.pl", "skoczow.pl", "starachowice.pl", "stargard.pl", "suwalki.pl", "swidnica.pl", "swiebodzin.pl", "swinoujscie.pl", "szczecin.pl", "szczytno.pl", "tarnobrzeg.pl", "tgory.pl", "turek.pl", "tychy.pl", "ustka.pl", "walbrzych.pl", "warmia.pl", "warszawa.pl", "waw.pl", "wegrow.pl", "wielun.pl", "wlocl.pl", "wloclawek.pl", "wodzislaw.pl", "wolomin.pl", "wroclaw.pl", "zachpomor.pl", "zagan.pl", "zarow.pl", "zgora.pl", "zgorzelec.pl", "pm", "pn", "gov.pn", "co.pn", "org.pn", "edu.pn", "net.pn", "post", "pr", "com.pr", "net.pr", "org.pr", "gov.pr", "edu.pr", "isla.pr", "pro.pr", "biz.pr", "info.pr", "name.pr", "est.pr", "prof.pr", "ac.pr", "pro", "aca.pro", "bar.pro", "cpa.pro", "jur.pro", "law.pro", "med.pro", "eng.pro", "ps", "edu.ps", "gov.ps", "sec.ps", "plo.ps", "com.ps", "org.ps", "net.ps", "pt", "net.pt", "gov.pt", "org.pt", "edu.pt", "int.pt", "publ.pt", "com.pt", "nome.pt", "pw", "co.pw", "ne.pw", "or.pw", "ed.pw", "go.pw", "belau.pw", "py", "com.py", "coop.py", "edu.py", "gov.py", "mil.py", "net.py", "org.py", "qa", "com.qa", "edu.qa", "gov.qa", "mil.qa", "name.qa", "net.qa", "org.qa", "sch.qa", "re", "com.re", "asso.re", "nom.re", "ro", "com.ro", "org.ro", "tm.ro", "nt.ro", "nom.ro", "info.ro", "rec.ro", "arts.ro", "firm.ro", "store.ro", "www.ro", "rs", "co.rs", "org.rs", "edu.rs", "ac.rs", "gov.rs", "in.rs", "ru", "ac.ru", "com.ru", "edu.ru", "int.ru", "net.ru", "org.ru", "pp.ru", "adygeya.ru", "altai.ru", "amur.ru", "arkhangelsk.ru", "astrakhan.ru", "bashkiria.ru", "belgorod.ru", "bir.ru", "bryansk.ru", "buryatia.ru", "cbg.ru", "chel.ru", "chelyabinsk.ru", "chita.ru", "chukotka.ru", "chuvashia.ru", "dagestan.ru", "dudinka.ru", "e-burg.ru", "grozny.ru", "irkutsk.ru", "ivanovo.ru", "izhevsk.ru", "jar.ru", "joshkar-ola.ru", "kalmykia.ru", "kaluga.ru", "kamchatka.ru", "karelia.ru", "kazan.ru", "kchr.ru", "kemerovo.ru", "khabarovsk.ru", "khakassia.ru", "khv.ru", "kirov.ru", "koenig.ru", "komi.ru", "kostroma.ru", "krasnoyarsk.ru", "kuban.ru", "kurgan.ru", "kursk.ru", "lipetsk.ru", "magadan.ru", "mari.ru", "mari-el.ru", "marine.ru", "mordovia.ru", "msk.ru", "murmansk.ru", "nalchik.ru", "nnov.ru", "nov.ru", "novosibirsk.ru", "nsk.ru", "omsk.ru", "orenburg.ru", "oryol.ru", "palana.ru", "penza.ru", "perm.ru", "ptz.ru", "rnd.ru", "ryazan.ru", "sakhalin.ru", "samara.ru", "saratov.ru", "simbirsk.ru", "smolensk.ru", "spb.ru", "stavropol.ru", "stv.ru", "surgut.ru", "tambov.ru", "tatarstan.ru", "tom.ru", "tomsk.ru", "tsaritsyn.ru", "tsk.ru", "tula.ru", "tuva.ru", "tver.ru", "tyumen.ru", "udm.ru", "udmurtia.ru", "ulan-ude.ru", "vladikavkaz.ru", "vladimir.ru", "vladivostok.ru", "volgograd.ru", "vologda.ru", "voronezh.ru", "vrn.ru", "vyatka.ru", "yakutia.ru", "yamal.ru", "yaroslavl.ru", "yekaterinburg.ru", "yuzhno-sakhalinsk.ru", "amursk.ru", "baikal.ru", "cmw.ru", "fareast.ru", "jamal.ru", "kms.ru", "k-uralsk.ru", "kustanai.ru", "kuzbass.ru", "mytis.ru", "nakhodka.ru", "nkz.ru", "norilsk.ru", "oskol.ru", "pyatigorsk.ru", "rubtsovsk.ru", "snz.ru", "syzran.ru", "vdonsk.ru", "zgrad.ru", "gov.ru", "mil.ru", "test.ru", "rw", "gov.rw", "net.rw", "edu.rw", "ac.rw", "com.rw", "co.rw", "int.rw", "mil.rw", "gouv.rw", "sa", "com.sa", "net.sa", "org.sa", "gov.sa", "med.sa", "pub.sa", "edu.sa", "sch.sa", "sb", "com.sb", "edu.sb", "gov.sb", "net.sb", "org.sb", "sc", "com.sc", "gov.sc", "net.sc", "org.sc", "edu.sc", "sd", "com.sd", "net.sd", "org.sd", "edu.sd", "med.sd", "tv.sd", "gov.sd", "info.sd", "se", "a.se", "ac.se", "b.se", "bd.se", "brand.se", "c.se", "d.se", "e.se", "f.se", "fh.se", "fhsk.se", "fhv.se", "g.se", "h.se", "i.se", "k.se", "komforb.se", "kommunalforbund.se", "komvux.se", "l.se", "lanbib.se", "m.se", "n.se", "naturbruksgymn.se", "o.se", "org.se", "p.se", "parti.se", "pp.se", "press.se", "r.se", "s.se", "t.se", "tm.se", "u.se", "w.se", "x.se", "y.se", "z.se", "sg", "com.sg", "net.sg", "org.sg", "gov.sg", "edu.sg", "per.sg", "sh", "com.sh", "net.sh", "gov.sh", "org.sh", "mil.sh", "si", "sj", "sk", "sl", "com.sl", "net.sl", "edu.sl", "gov.sl", "org.sl", "sm", "sn", "art.sn", "com.sn", "edu.sn", "gouv.sn", "org.sn", "perso.sn", "univ.sn", "so", "com.so", "net.so", "org.so", "sr", "st", "co.st", "com.st", "consulado.st", "edu.st", "embaixada.st", "gov.st", "mil.st", "net.st", "org.st", "principe.st", "saotome.st", "store.st", "su", "adygeya.su", "arkhangelsk.su", "balashov.su", "bashkiria.su", "bryansk.su", "dagestan.su", "grozny.su", "ivanovo.su", "kalmykia.su", "kaluga.su", "karelia.su", "khakassia.su", "krasnodar.su", "kurgan.su", "lenug.su", "mordovia.su", "msk.su", "murmansk.su", "nalchik.su", "nov.su", "obninsk.su", "penza.su", "pokrovsk.su", "sochi.su", "spb.su", "togliatti.su", "troitsk.su", "tula.su", "tuva.su", "vladikavkaz.su", "vladimir.su", "vologda.su", "sv", "com.sv", "edu.sv", "gob.sv", "org.sv", "red.sv", "sx", "gov.sx", "sy", "edu.sy", "gov.sy", "net.sy", "mil.sy", "com.sy", "org.sy", "sz", "co.sz", "ac.sz", "org.sz", "tc", "td", "tel", "tf", "tg", "th", "ac.th", "co.th", "go.th", "in.th", "mi.th", "net.th", "or.th", "tj", "ac.tj", "biz.tj", "co.tj", "com.tj", "edu.tj", "go.tj", "gov.tj", "int.tj", "mil.tj", "name.tj", "net.tj", "nic.tj", "org.tj", "test.tj", "web.tj", "tk", "tl", "gov.tl", "tm", "com.tm", "co.tm", "org.tm", "net.tm", "nom.tm", "gov.tm", "mil.tm", "edu.tm", "tn", "com.tn", "ens.tn", "fin.tn", "gov.tn", "ind.tn", "intl.tn", "nat.tn", "net.tn", "org.tn", "info.tn", "perso.tn", "tourism.tn", "edunet.tn", "rnrt.tn", "rns.tn", "rnu.tn", "mincom.tn", "agrinet.tn", "defense.tn", "turen.tn", "to", "com.to", "gov.to", "net.to", "org.to", "edu.to", "mil.to", "tp", "tr", "com.tr", "info.tr", "biz.tr", "net.tr", "org.tr", "web.tr", "gen.tr", "tv.tr", "av.tr", "dr.tr", "bbs.tr", "name.tr", "tel.tr", "gov.tr", "bel.tr", "pol.tr", "mil.tr", "k12.tr", "edu.tr", "kep.tr", "nc.tr", "gov.nc.tr", "travel", "tt", "co.tt", "com.tt", "org.tt", "net.tt", "biz.tt", "info.tt", "pro.tt", "int.tt", "coop.tt", "jobs.tt", "mobi.tt", "travel.tt", "museum.tt", "aero.tt", "name.tt", "gov.tt", "edu.tt", "tv", "tw", "edu.tw", "gov.tw", "mil.tw", "com.tw", "net.tw", "org.tw", "idv.tw", "game.tw", "ebiz.tw", "club.tw", "xn--zf0ao64a.tw", "xn--uc0atv.tw", "xn--czrw28b.tw", "tz", "ac.tz", "co.tz", "go.tz", "hotel.tz", "info.tz", "me.tz", "mil.tz", "mobi.tz", "ne.tz", "or.tz", "sc.tz", "tv.tz", "ua", "com.ua", "edu.ua", "gov.ua", "in.ua", "net.ua", "org.ua", "cherkassy.ua", "cherkasy.ua", "chernigov.ua", "chernihiv.ua", "chernivtsi.ua", "chernovtsy.ua", "ck.ua", "cn.ua", "cr.ua", "crimea.ua", "cv.ua", "dn.ua", "dnepropetrovsk.ua", "dnipropetrovsk.ua", "dominic.ua", "donetsk.ua", "dp.ua", "if.ua", "ivano-frankivsk.ua", "kh.ua", "kharkiv.ua", "kharkov.ua", "kherson.ua", "khmelnitskiy.ua", "khmelnytskyi.ua", "kiev.ua", "kirovograd.ua", "km.ua", "kr.ua", "krym.ua", "ks.ua", "kv.ua", "kyiv.ua", "lg.ua", "lt.ua", "lugansk.ua", "lutsk.ua", "lv.ua", "lviv.ua", "mk.ua", "mykolaiv.ua", "nikolaev.ua", "od.ua", "odesa.ua", "odessa.ua", "pl.ua", "poltava.ua", "rivne.ua", "rovno.ua", "rv.ua", "sb.ua", "sebastopol.ua", "sevastopol.ua", "sm.ua", "sumy.ua", "te.ua", "ternopil.ua", "uz.ua", "uzhgorod.ua", "vinnica.ua", "vinnytsia.ua", "vn.ua", "volyn.ua", "yalta.ua", "zaporizhzhe.ua", "zaporizhzhia.ua", "zhitomir.ua", "zhytomyr.ua", "zp.ua", "zt.ua", "ug", "co.ug", "or.ug", "ac.ug", "sc.ug", "go.ug", "ne.ug", "com.ug", "org.ug", "uk", "ac.uk", "co.uk", "gov.uk", "ltd.uk", "me.uk", "net.uk", "nhs.uk", "org.uk", "plc.uk", "police.uk", "*.sch.uk", "us", "dni.us", "fed.us", "isa.us", "kids.us", "nsn.us", "ak.us", "al.us", "ar.us", "as.us", "az.us", "ca.us", "co.us", "ct.us", "dc.us", "de.us", "fl.us", "ga.us", "gu.us", "hi.us", "ia.us", "id.us", "il.us", "in.us", "ks.us", "ky.us", "la.us", "ma.us", "md.us", "me.us", "mi.us", "mn.us", "mo.us", "ms.us", "mt.us", "nc.us", "nd.us", "ne.us", "nh.us", "nj.us", "nm.us", "nv.us", "ny.us", "oh.us", "ok.us", "or.us", "pa.us", "pr.us", "ri.us", "sc.us", "sd.us", "tn.us", "tx.us", "ut.us", "vi.us", "vt.us", "va.us", "wa.us", "wi.us", "wv.us", "wy.us", "k12.ak.us", "k12.al.us", "k12.ar.us", "k12.as.us", "k12.az.us", "k12.ca.us", "k12.co.us", "k12.ct.us", "k12.dc.us", "k12.de.us", "k12.fl.us", "k12.ga.us", "k12.gu.us", "k12.ia.us", "k12.id.us", "k12.il.us", "k12.in.us", "k12.ks.us", "k12.ky.us", "k12.la.us", "k12.ma.us", "k12.md.us", "k12.me.us", "k12.mi.us", "k12.mn.us", "k12.mo.us", "k12.ms.us", "k12.mt.us", "k12.nc.us", "k12.ne.us", "k12.nh.us", "k12.nj.us", "k12.nm.us", "k12.nv.us", "k12.ny.us", "k12.oh.us", "k12.ok.us", "k12.or.us", "k12.pa.us", "k12.pr.us", "k12.ri.us", "k12.sc.us", "k12.tn.us", "k12.tx.us", "k12.ut.us", "k12.vi.us", "k12.vt.us", "k12.va.us", "k12.wa.us", "k12.wi.us", "k12.wy.us", "cc.ak.us", "cc.al.us", "cc.ar.us", "cc.as.us", "cc.az.us", "cc.ca.us", "cc.co.us", "cc.ct.us", "cc.dc.us", "cc.de.us", "cc.fl.us", "cc.ga.us", "cc.gu.us", "cc.hi.us", "cc.ia.us", "cc.id.us", "cc.il.us", "cc.in.us", "cc.ks.us", "cc.ky.us", "cc.la.us", "cc.ma.us", "cc.md.us", "cc.me.us", "cc.mi.us", "cc.mn.us", "cc.mo.us", "cc.ms.us", "cc.mt.us", "cc.nc.us", "cc.nd.us", "cc.ne.us", "cc.nh.us", "cc.nj.us", "cc.nm.us", "cc.nv.us", "cc.ny.us", "cc.oh.us", "cc.ok.us", "cc.or.us", "cc.pa.us", "cc.pr.us", "cc.ri.us", "cc.sc.us", "cc.sd.us", "cc.tn.us", "cc.tx.us", "cc.ut.us", "cc.vi.us", "cc.vt.us", "cc.va.us", "cc.wa.us", "cc.wi.us", "cc.wv.us", "cc.wy.us", "lib.ak.us", "lib.al.us", "lib.ar.us", "lib.as.us", "lib.az.us", "lib.ca.us", "lib.co.us", "lib.ct.us", "lib.dc.us", "lib.de.us", "lib.fl.us", "lib.ga.us", "lib.gu.us", "lib.hi.us", "lib.ia.us", "lib.id.us", "lib.il.us", "lib.in.us", "lib.ks.us", "lib.ky.us", "lib.la.us", "lib.ma.us", "lib.md.us", "lib.me.us", "lib.mi.us", "lib.mn.us", "lib.mo.us", "lib.ms.us", "lib.mt.us", "lib.nc.us", "lib.nd.us", "lib.ne.us", "lib.nh.us", "lib.nj.us", "lib.nm.us", "lib.nv.us", "lib.ny.us", "lib.oh.us", "lib.ok.us", "lib.or.us", "lib.pa.us", "lib.pr.us", "lib.ri.us", "lib.sc.us", "lib.sd.us", "lib.tn.us", "lib.tx.us", "lib.ut.us", "lib.vi.us", "lib.vt.us", "lib.va.us", "lib.wa.us", "lib.wi.us", "lib.wy.us", "pvt.k12.ma.us", "chtr.k12.ma.us", "paroch.k12.ma.us", "uy", "com.uy", "edu.uy", "gub.uy", "mil.uy", "net.uy", "org.uy", "uz", "co.uz", "com.uz", "net.uz", "org.uz", "va", "vc", "com.vc", "net.vc", "org.vc", "gov.vc", "mil.vc", "edu.vc", "ve", "arts.ve", "co.ve", "com.ve", "e12.ve", "edu.ve", "firm.ve", "gob.ve", "gov.ve", "info.ve", "int.ve", "mil.ve", "net.ve", "org.ve", "rec.ve", "store.ve", "tec.ve", "web.ve", "vg", "vi", "co.vi", "com.vi", "k12.vi", "net.vi", "org.vi", "vn", "com.vn", "net.vn", "org.vn", "edu.vn", "gov.vn", "int.vn", "ac.vn", "biz.vn", "info.vn", "name.vn", "pro.vn", "health.vn", "vu", "com.vu", "edu.vu", "net.vu", "org.vu", "wf", "ws", "com.ws", "net.ws", "org.ws", "gov.ws", "edu.ws", "yt", "xn--mgbaam7a8h", "xn--y9a3aq", "xn--54b7fta0cc", "xn--90ais", "xn--fiqs8s", "xn--fiqz9s", "xn--lgbbat1ad8j", "xn--wgbh1c", "xn--node", "xn--qxam", "xn--j6w193g", "xn--h2brj9c", "xn--mgbbh1a71e", "xn--fpcrj9c3d", "xn--gecrj9c", "xn--s9brj9c", "xn--45brj9c", "xn--xkc2dl3a5ee0h", "xn--mgba3a4f16a", "xn--mgba3a4fra", "xn--mgbtx2b", "xn--mgbayh7gpa", "xn--3e0b707e", "xn--80ao21a", "xn--fzc2c9e2c", "xn--xkc2al3hye2a", "xn--mgbc0a9azcg", "xn--d1alf", "xn--l1acc", "xn--mix891f", "xn--mix082f", "xn--mgbx4cd0ab", "xn--mgb9awbf", "xn--mgbai9azgqp6j", "xn--mgbai9a5eva00b", "xn--ygbi2ammx", "xn--90a3ac", "xn--o1ac.xn--90a3ac", "xn--c1avg.xn--90a3ac", "xn--90azh.xn--90a3ac", "xn--d1at.xn--90a3ac", "xn--o1ach.xn--90a3ac", "xn--80au.xn--90a3ac", "xn--p1ai", "xn--wgbl6a", "xn--mgberp4a5d4ar", "xn--mgberp4a5d4a87g", "xn--mgbqly7c0a67fbc", "xn--mgbqly7cvafr", "xn--mgbpl2fh", "xn--yfro4i67o", "xn--clchc0ea0b2g2a9gcd", "xn--ogbpf8fl", "xn--mgbtf8fl", "xn--o3cw4h", "xn--pgbs0dh", "xn--kpry57d", "xn--kprw13d", "xn--nnx388a", "xn--j1amh", "xn--mgb2ddes", "xxx", "*.ye", "ac.za", "agrica.za", "alt.za", "co.za", "edu.za", "gov.za", "grondar.za", "law.za", "mil.za", "net.za", "ngo.za", "nis.za", "nom.za", "org.za", "school.za", "tm.za", "web.za", "*.zm", "*.zw", "aaa", "aarp", "abarth", "abb", "abbott", "abbvie", "abc", "able", "abogado", "abudhabi", "academy", "accenture", "accountant", "accountants", "aco", "active", "actor", "adac", "ads", "adult", "aeg", "aetna", "afamilycompany", "afl", "africa", "africamagic", "agakhan", "agency", "aig", "aigo", "airbus", "airforce", "airtel", "akdn", "alfaromeo", "alibaba", "alipay", "allfinanz", "allstate", "ally", "alsace", "alstom", "americanexpress", "americanfamily", "amex", "amfam", "amica", "amsterdam", "analytics", "android", "anquan", "anz", "aol", "apartments", "app", "apple", "aquarelle", "aramco", "archi", "army", "arte", "asda", "associates", "athleta", "attorney", "auction", "audi", "audible", "audio", "auspost", "author", "auto", "autos", "avianca", "aws", "axa", "azure", "baby", "baidu", "banamex", "bananarepublic", "band", "bank", "bar", "barcelona", "barclaycard", "barclays", "barefoot", "bargains", "baseball", "basketball", "bauhaus", "bayern", "bbc", "bbt", "bbva", "bcg", "bcn", "beats", "beer", "bentley", "berlin", "best", "bestbuy", "bet", "bharti", "bible", "bid", "bike", "bing", "bingo", "bio", "black", "blackfriday", "blanco", "blockbuster", "blog", "bloomberg", "blue", "bms", "bmw", "bnl", "bnpparibas", "boats", "boehringer", "bofa", "bom", "bond", "boo", "book", "booking", "boots", "bosch", "bostik", "bot", "boutique", "bradesco", "bridgestone", "broadway", "broker", "brother", "brussels", "budapest", "bugatti", "build", "builders", "business", "buy", "buzz", "bzh", "cab", "cafe", "cal", "call", "calvinklein", "camera", "camp", "cancerresearch", "canon", "capetown", "capital", "capitalone", "car", "caravan", "cards", "care", "career", "careers", "cars", "cartier", "casa", "case", "caseih", "cash", "casino", "catering", "catholic", "cba", "cbn", "cbre", "cbs", "ceb", "center", "ceo", "cern", "cfa", "cfd", "chanel", "channel", "chase", "chat", "cheap", "chintai", "chloe", "christmas", "chrome", "chrysler", "church", "cipriani", "circle", "cisco", "citadel", "citi", "citic", "city", "cityeats", "claims", "cleaning", "click", "clinic", "clinique", "clothing", "cloud", "club", "clubmed", "coach", "codes", "coffee", "college", "cologne", "comcast", "commbank", "community", "company", "compare", "computer", "comsec", "condos", "construction", "consulting", "contact", "contractors", "cooking", "cookingchannel", "cool", "corsica", "country", "coupon", "coupons", "courses", "credit", "creditcard", "creditunion", "cricket", "crown", "crs", "cruises", "csc", "cuisinella", "cymru", "cyou", "dabur", "dad", "dance", "date", "dating", "datsun", "day", "dclk", "dds", "deal", "dealer", "deals", "degree", "delivery", "dell", "deloitte", "delta", "democrat", "dental", "dentist", "desi", "design", "dev", "dhl", "diamonds", "diet", "digital", "direct", "directory", "discount", "discover", "dish", "diy", "dnp", "docs", "dodge", "dog", "doha", "domains", "doosan", "dot", "download", "drive", "dstv", "dtv", "dubai", "duck", "dunlop", "duns", "dupont", "durban", "dvag", "dwg", "earth", "eat", "edeka", "education", "email", "emerck", "emerson", "energy", "engineer", "engineering", "enterprises", "epost", "epson", "equipment", "ericsson", "erni", "esq", "estate", "esurance", "etisalat", "eurovision", "eus", "events", "everbank", "exchange", "expert", "exposed", "express", "extraspace", "fage", "fail", "fairwinds", "faith", "family", "fan", "fans", "farm", "farmers", "fashion", "fast", "fedex", "feedback", "ferrari", "ferrero", "fiat", "fidelity", "fido", "film", "final", "finance", "financial", "fire", "firestone", "firmdale", "fish", "fishing", "fit", "fitness", "flickr", "flights", "flir", "florist", "flowers", "flsmidth", "fly", "foo", "foodnetwork", "football", "ford", "forex", "forsale", "forum", "foundation", "fox", "fresenius", "frl", "frogans", "frontdoor", "frontier", "ftr", "fujitsu", "fujixerox", "fund", "furniture", "futbol", "fyi", "gal", "gallery", "gallo", "gallup", "game", "games", "gap", "garden", "gbiz", "gdn", "gea", "gent", "genting", "george", "ggee", "gift", "gifts", "gives", "giving", "glade", "glass", "gle", "global", "globo", "gmail", "gmo", "gmx", "godaddy", "gold", "goldpoint", "golf", "goo", "goodhands", "goodyear", "goog", "google", "gop", "got", "gotv", "grainger", "graphics", "gratis", "green", "gripe", "group", "guardian", "gucci", "guge", "guide", "guitars", "guru", "hamburg", "hangout", "haus", "hbo", "hdfc", "hdfcbank", "health", "healthcare", "help", "helsinki", "here", "hermes", "hgtv", "hiphop", "hisamitsu", "hitachi", "hiv", "hkt", "hockey", "holdings", "holiday", "homedepot", "homegoods", "homes", "homesense", "honda", "honeywell", "horse", "host", "hosting", "hot", "hoteles", "hotmail", "house", "how", "hsbc", "htc", "hughes", "hyatt", "hyundai", "ibm", "icbc", "ice", "icu", "ieee", "ifm", "iinet", "ikano", "imamat", "imdb", "immo", "immobilien", "industries", "infiniti", "ing", "ink", "institute", "insurance", "insure", "intel", "international", "intuit", "investments", "ipiranga", "irish", "iselect", "ismaili", "ist", "istanbul", "itau", "itv", "iveco", "iwc", "jaguar", "java", "jcb", "jcp", "jeep", "jetzt", "jewelry", "jio", "jlc", "jll", "jmp", "jnj", "joburg", "jot", "joy", "jpmorgan", "jprs", "juegos", "juniper", "kaufen", "kddi", "kerryhotels", "kerrylogistics", "kerryproperties", "kfh", "kia", "kim", "kinder", "kindle", "kitchen", "kiwi", "koeln", "komatsu", "kosher", "kpmg", "kpn", "krd", "kred", "kuokgroup", "kyknet", "kyoto", "lacaixa", "ladbrokes", "lamborghini", "lamer", "lancaster", "lancia", "lancome", "land", "landrover", "lanxess", "lasalle", "lat", "latino", "latrobe", "law", "lawyer", "lds", "lease", "leclerc", "lefrak", "legal", "lego", "lexus", "lgbt", "liaison", "lidl", "life", "lifeinsurance", "lifestyle", "lighting", "like", "lilly", "limited", "limo", "lincoln", "linde", "link", "lipsy", "live", "living", "lixil", "loan", "loans", "locker", "locus", "loft", "lol", "london", "lotte", "lotto", "love", "lpl", "lplfinancial", "ltd", "ltda", "lundbeck", "lupin", "luxe", "luxury", "macys", "madrid", "maif", "maison", "makeup", "man", "management", "mango", "market", "marketing", "markets", "marriott", "marshalls", "maserati", "mattel", "mba", "mcd", "mcdonalds", "mckinsey", "med", "media", "meet", "melbourne", "meme", "memorial", "men", "menu", "meo", "metlife", "miami", "microsoft", "mini", "mint", "mit", "mitsubishi", "mlb", "mls", "mma", "mnet", "mobily", "moda", "moe", "moi", "mom", "monash", "money", "monster", "montblanc", "mopar", "mormon", "mortgage", "moscow", "moto", "motorcycles", "mov", "movie", "movistar", "msd", "mtn", "mtpc", "mtr", "multichoice", "mutual", "mutuelle", "mzansimagic", "nab", "nadex", "nagoya", "naspers", "nationwide", "natura", "navy", "nba", "nec", "netbank", "netflix", "network", "neustar", "new", "newholland", "news", "next", "nextdirect", "nexus", "nfl", "ngo", "nhk", "nico", "nike", "nikon", "ninja", "nissan", "nissay", "nokia", "northwesternmutual", "norton", "now", "nowruz", "nowtv", "nra", "nrw", "ntt", "nyc", "obi", "observer", "off", "office", "okinawa", "olayan", "olayangroup", "oldnavy", "ollo", "omega", "one", "ong", "onl", "online", "onyourside", "ooo", "open", "oracle", "orange", "organic", "orientexpress", "origins", "osaka", "otsuka", "ott", "ovh", "page", "pamperedchef", "panasonic", "panerai", "paris", "pars", "partners", "parts", "party", "passagens", "pay", "payu", "pccw", "pet", "pfizer", "pharmacy", "philips", "photo", "photography", "photos", "physio", "piaget", "pics", "pictet", "pictures", "pid", "pin", "ping", "pink", "pioneer", "pizza", "place", "play", "playstation", "plumbing", "plus", "pnc", "pohl", "poker", "politie", "porn", "pramerica", "praxi", "press", "prime", "prod", "productions", "prof", "progressive", "promo", "properties", "property", "protection", "pru", "prudential", "pub", "pwc", "qpon", "quebec", "quest", "qvc", "racing", "raid", "read", "realestate", "realtor", "realty", "recipes", "red", "redstone", "redumbrella", "rehab", "reise", "reisen", "reit", "reliance", "ren", "rent", "rentals", "repair", "report", "republican", "rest", "restaurant", "review", "reviews", "rexroth", "rich", "richardli", "ricoh", "rightathome", "ril", "rio", "rip", "rocher", "rocks", "rodeo", "rogers", "room", "rsvp", "ruhr", "run", "rwe", "ryukyu", "saarland", "safe", "safety", "sakura", "sale", "salon", "samsclub", "samsung", "sandvik", "sandvikcoromant", "sanofi", "sap", "sapo", "sarl", "sas", "save", "saxo", "sbi", "sbs", "sca", "scb", "schaeffler", "schmidt", "scholarships", "school", "schule", "schwarz", "science", "scjohnson", "scor", "scot", "seat", "secure", "security", "seek", "select", "sener", "services", "ses", "seven", "sew", "sex", "sexy", "sfr", "shangrila", "sharp", "shaw", "shell", "shia", "shiksha", "shoes", "shouji", "show", "showtime", "shriram", "silk", "sina", "singles", "site", "ski", "skin", "sky", "skype", "sling", "smart", "smile", "sncf", "soccer", "social", "softbank", "software", "sohu", "solar", "solutions", "song", "sony", "soy", "space", "spiegel", "spot", "spreadbetting", "srl", "srt", "stada", "staples", "star", "starhub", "statebank", "statefarm", "statoil", "stc", "stcgroup", "stockholm", "storage", "store", "studio", "study", "style", "sucks", "supersport", "supplies", "supply", "support", "surf", "surgery", "suzuki", "swatch", "swiftcover", "swiss", "sydney", "symantec", "systems", "tab", "taipei", "talk", "taobao", "target", "tatamotors", "tatar", "tattoo", "tax", "taxi", "tci", "tdk", "team", "tech", "technology", "telecity", "telefonica", "temasek", "tennis", "teva", "thd", "theater", "theatre", "theguardian", "tiaa", "tickets", "tienda", "tiffany", "tips", "tires", "tirol", "tjmaxx", "tjx", "tkmaxx", "tmall", "today", "tokyo", "tools", "top", "toray", "toshiba", "total", "tours", "town", "toyota", "toys", "trade", "trading", "training", "travelchannel", "travelers", "travelersinsurance", "trust", "trv", "tube", "tui", "tunes", "tushu", "tvs", "ubank", "ubs", "uconnect", "unicom", "university", "uno", "uol", "ups", "vacations", "vana", "vanguard", "vegas", "ventures", "verisign", "versicherung", "vet", "viajes", "video", "vig", "viking", "villas", "vin", "vip", "virgin", "visa", "vision", "vista", "vistaprint", "viva", "vivo", "vlaanderen", "vodka", "volkswagen", "vote", "voting", "voto", "voyage", "vuelos", "wales", "walmart", "walter", "wang", "wanggou", "warman", "watch", "watches", "weather", "weatherchannel", "webcam", "weber", "website", "wed", "wedding", "weibo", "weir", "whoswho", "wien", "wiki", "williamhill", "win", "windows", "wine", "winners", "wme", "wolterskluwer", "woodside", "work", "works", "world", "wow", "wtc", "wtf", "xbox", "xerox", "xfinity", "xihuan", "xin", "xn--11b4c3d", "xn--1ck2e1b", "xn--1qqw23a", "xn--30rr7y", "xn--3bst00m", "xn--3ds443g", "xn--3oq18vl8pn36a", "xn--3pxu8k", "xn--42c2d9a", "xn--45q11c", "xn--4gbrim", "xn--4gq48lf9j", "xn--55qw42g", "xn--55qx5d", "xn--5su34j936bgsg", "xn--5tzm5g", "xn--6frz82g", "xn--6qq986b3xl", "xn--80adxhks", "xn--80aqecdr1a", "xn--80asehdb", "xn--80aswg", "xn--8y0a063a", "xn--9dbq2a", "xn--9et52u", "xn--9krt00a", "xn--b4w605ferd", "xn--bck1b9a5dre4c", "xn--c1avg", "xn--c2br7g", "xn--cck2b3b", "xn--cg4bki", "xn--czr694b", "xn--czrs0t", "xn--czru2d", "xn--d1acj3b", "xn--eckvdtc9d", "xn--efvy88h", "xn--estv75g", "xn--fct429k", "xn--fhbei", "xn--fiq228c5hs", "xn--fiq64b", "xn--fjq720a", "xn--flw351e", "xn--fzys8d69uvgm", "xn--g2xx48c", "xn--gckr3f0f", "xn--gk3at1e", "xn--hxt814e", "xn--i1b6b1a6a2e", "xn--imr513n", "xn--io0a7i", "xn--j1aef", "xn--jlq61u9w7b", "xn--jvr189m", "xn--kcrx77d1x4a", "xn--kpu716f", "xn--kput3i", "xn--mgba3a3ejt", "xn--mgba7c0bbn0a", "xn--mgbaakc7dvf", "xn--mgbab2bd", "xn--mgbb9fbpob", "xn--mgbca7dzdo", "xn--mgbi4ecexp", "xn--mgbt3dhd", "xn--mk1bu44c", "xn--mxtq1m", "xn--ngbc5azd", "xn--ngbe9e0a", "xn--nqv7f", "xn--nqv7fs00ema", "xn--nyqy26a", "xn--p1acf", "xn--pbt977c", "xn--pssy2u", "xn--q9jyb4c", "xn--qcka1pmc", "xn--rhqv96g", "xn--rovu88b", "xn--ses554g", "xn--t60b56a", "xn--tckwe", "xn--tiq49xqyj", "xn--unup4y", "xn--vermgensberater-ctb", "xn--vermgensberatung-pwb", "xn--vhquv", "xn--vuq861b", "xn--w4r85el8fhu5dnra", "xn--w4rs40l", "xn--xhq521b", "xn--zfr164b", "xperia", "xyz", "yachts", "yahoo", "yamaxun", "yandex", "yodobashi", "yoga", "yokohama", "you", "youtube", "yun", "zappos", "zara", "zero", "zip", "zippo", "zone", "zuerich", "cloudfront.net", "ap-northeast-1.compute.amazonaws.com", "ap-southeast-1.compute.amazonaws.com", "ap-southeast-2.compute.amazonaws.com", "cn-north-1.compute.amazonaws.cn", "compute.amazonaws.cn", "compute.amazonaws.com", "compute-1.amazonaws.com", "eu-west-1.compute.amazonaws.com", "eu-central-1.compute.amazonaws.com", "sa-east-1.compute.amazonaws.com", "us-east-1.amazonaws.com", "us-gov-west-1.compute.amazonaws.com", "us-west-1.compute.amazonaws.com", "us-west-2.compute.amazonaws.com", "z-1.compute-1.amazonaws.com", "z-2.compute-1.amazonaws.com", "elasticbeanstalk.com", "elb.amazonaws.com", "s3.amazonaws.com", "s3-ap-northeast-1.amazonaws.com", "s3-ap-southeast-1.amazonaws.com", "s3-ap-southeast-2.amazonaws.com", "s3-external-1.amazonaws.com", "s3-external-2.amazonaws.com", "s3-fips-us-gov-west-1.amazonaws.com", "s3-eu-central-1.amazonaws.com", "s3-eu-west-1.amazonaws.com", "s3-sa-east-1.amazonaws.com", "s3-us-gov-west-1.amazonaws.com", "s3-us-west-1.amazonaws.com", "s3-us-west-2.amazonaws.com", "s3.cn-north-1.amazonaws.com.cn", "s3.eu-central-1.amazonaws.com", "betainabox.com", "ae.org", "ar.com", "br.com", "cn.com", "com.de", "com.se", "de.com", "eu.com", "gb.com", "gb.net", "hu.com", "hu.net", "jp.net", "jpn.com", "kr.com", "mex.com", "no.com", "qc.com", "ru.com", "sa.com", "se.com", "se.net", "uk.com", "uk.net", "us.com", "uy.com", "za.bz", "za.com", "africa.com", "gr.com", "in.net", "us.org", "co.com", "c.la", "cloudcontrolled.com", "cloudcontrolapp.com", "co.ca", "c.cdn77.org", "cdn77-ssl.net", "r.cdn77.net", "rsc.cdn77.org", "ssl.origin.cdn77-secure.org", "co.nl", "co.no", "*.platform.sh", "cupcake.is", "dreamhosters.com", "duckdns.org", "dyndns-at-home.com", "dyndns-at-work.com", "dyndns-blog.com", "dyndns-free.com", "dyndns-home.com", "dyndns-ip.com", "dyndns-mail.com", "dyndns-office.com", "dyndns-pics.com", "dyndns-remote.com", "dyndns-server.com", "dyndns-web.com", "dyndns-wiki.com", "dyndns-work.com", "dyndns.biz", "dyndns.info", "dyndns.org", "dyndns.tv", "at-band-camp.net", "ath.cx", "barrel-of-knowledge.info", "barrell-of-knowledge.info", "better-than.tv", "blogdns.com", "blogdns.net", "blogdns.org", "blogsite.org", "boldlygoingnowhere.org", "broke-it.net", "buyshouses.net", "cechire.com", "dnsalias.com", "dnsalias.net", "dnsalias.org", "dnsdojo.com", "dnsdojo.net", "dnsdojo.org", "does-it.net", "doesntexist.com", "doesntexist.org", "dontexist.com", "dontexist.net", "dontexist.org", "doomdns.com", "doomdns.org", "dvrdns.org", "dyn-o-saur.com", "dynalias.com", "dynalias.net", "dynalias.org", "dynathome.net", "dyndns.ws", "endofinternet.net", "endofinternet.org", "endoftheinternet.org", "est-a-la-maison.com", "est-a-la-masion.com", "est-le-patron.com", "est-mon-blogueur.com", "for-better.biz", "for-more.biz", "for-our.info", "for-some.biz", "for-the.biz", "forgot.her.name", "forgot.his.name", "from-ak.com", "from-al.com", "from-ar.com", "from-az.net", "from-ca.com", "from-co.net", "from-ct.com", "from-dc.com", "from-de.com", "from-fl.com", "from-ga.com", "from-hi.com", "from-ia.com", "from-id.com", "from-il.com", "from-in.com", "from-ks.com", "from-ky.com", "from-la.net", "from-ma.com", "from-md.com", "from-me.org", "from-mi.com", "from-mn.com", "from-mo.com", "from-ms.com", "from-mt.com", "from-nc.com", "from-nd.com", "from-ne.com", "from-nh.com", "from-nj.com", "from-nm.com", "from-nv.com", "from-ny.net", "from-oh.com", "from-ok.com", "from-or.com", "from-pa.com", "from-pr.com", "from-ri.com", "from-sc.com", "from-sd.com", "from-tn.com", "from-tx.com", "from-ut.com", "from-va.com", "from-vt.com", "from-wa.com", "from-wi.com", "from-wv.com", "from-wy.com", "ftpaccess.cc", "fuettertdasnetz.de", "game-host.org", "game-server.cc", "getmyip.com", "gets-it.net", "go.dyndns.org", "gotdns.com", "gotdns.org", "groks-the.info", "groks-this.info", "ham-radio-op.net", "here-for-more.info", "hobby-site.com", "hobby-site.org", "home.dyndns.org", "homedns.org", "homeftp.net", "homeftp.org", "homeip.net", "homelinux.com", "homelinux.net", "homelinux.org", "homeunix.com", "homeunix.net", "homeunix.org", "iamallama.com", "in-the-band.net", "is-a-anarchist.com", "is-a-blogger.com", "is-a-bookkeeper.com", "is-a-bruinsfan.org", "is-a-bulls-fan.com", "is-a-candidate.org", "is-a-caterer.com", "is-a-celticsfan.org", "is-a-chef.com", "is-a-chef.net", "is-a-chef.org", "is-a-conservative.com", "is-a-cpa.com", "is-a-cubicle-slave.com", "is-a-democrat.com", "is-a-designer.com", "is-a-doctor.com", "is-a-financialadvisor.com", "is-a-geek.com", "is-a-geek.net", "is-a-geek.org", "is-a-green.com", "is-a-guru.com", "is-a-hard-worker.com", "is-a-hunter.com", "is-a-knight.org", "is-a-landscaper.com", "is-a-lawyer.com", "is-a-liberal.com", "is-a-libertarian.com", "is-a-linux-user.org", "is-a-llama.com", "is-a-musician.com", "is-a-nascarfan.com", "is-a-nurse.com", "is-a-painter.com", "is-a-patsfan.org", "is-a-personaltrainer.com", "is-a-photographer.com", "is-a-player.com", "is-a-republican.com", "is-a-rockstar.com", "is-a-socialist.com", "is-a-soxfan.org", "is-a-student.com", "is-a-teacher.com", "is-a-techie.com", "is-a-therapist.com", "is-an-accountant.com", "is-an-actor.com", "is-an-actress.com", "is-an-anarchist.com", "is-an-artist.com", "is-an-engineer.com", "is-an-entertainer.com", "is-by.us", "is-certified.com", "is-found.org", "is-gone.com", "is-into-anime.com", "is-into-cars.com", "is-into-cartoons.com", "is-into-games.com", "is-leet.com", "is-lost.org", "is-not-certified.com", "is-saved.org", "is-slick.com", "is-uberleet.com", "is-very-bad.org", "is-very-evil.org", "is-very-good.org", "is-very-nice.org", "is-very-sweet.org", "is-with-theband.com", "isa-geek.com", "isa-geek.net", "isa-geek.org", "isa-hockeynut.com", "issmarterthanyou.com", "isteingeek.de", "istmein.de", "kicks-ass.net", "kicks-ass.org", "knowsitall.info", "land-4-sale.us", "lebtimnetz.de", "leitungsen.de", "likes-pie.com", "likescandy.com", "merseine.nu", "mine.nu", "misconfused.org", "mypets.ws", "myphotos.cc", "neat-url.com", "office-on-the.net", "on-the-web.tv", "podzone.net", "podzone.org", "readmyblog.org", "saves-the-whales.com", "scrapper-site.net", "scrapping.cc", "selfip.biz", "selfip.com", "selfip.info", "selfip.net", "selfip.org", "sells-for-less.com", "sells-for-u.com", "sells-it.net", "sellsyourhome.org", "servebbs.com", "servebbs.net", "servebbs.org", "serveftp.net", "serveftp.org", "servegame.org", "shacknet.nu", "simple-url.com", "space-to-rent.com", "stuff-4-sale.org", "stuff-4-sale.us", "teaches-yoga.com", "thruhere.net", "traeumtgerade.de", "webhop.biz", "webhop.info", "webhop.net", "webhop.org", "worse-than.tv", "writesthisblog.com", "eu.org", "al.eu.org", "asso.eu.org", "at.eu.org", "au.eu.org", "be.eu.org", "bg.eu.org", "ca.eu.org", "cd.eu.org", "ch.eu.org", "cn.eu.org", "cy.eu.org", "cz.eu.org", "de.eu.org", "dk.eu.org", "edu.eu.org", "ee.eu.org", "es.eu.org", "fi.eu.org", "fr.eu.org", "gr.eu.org", "hr.eu.org", "hu.eu.org", "ie.eu.org", "il.eu.org", "in.eu.org", "int.eu.org", "is.eu.org", "it.eu.org", "jp.eu.org", "kr.eu.org", "lt.eu.org", "lu.eu.org", "lv.eu.org", "mc.eu.org", "me.eu.org", "mk.eu.org", "mt.eu.org", "my.eu.org", "net.eu.org", "ng.eu.org", "nl.eu.org", "no.eu.org", "nz.eu.org", "paris.eu.org", "pl.eu.org", "pt.eu.org", "q-a.eu.org", "ro.eu.org", "ru.eu.org", "se.eu.org", "si.eu.org", "sk.eu.org", "tr.eu.org", "uk.eu.org", "us.eu.org", "a.ssl.fastly.net", "b.ssl.fastly.net", "global.ssl.fastly.net", "a.prod.fastly.net", "global.prod.fastly.net", "firebaseapp.com", "flynnhub.com", "service.gov.uk", "github.io", "githubusercontent.com", "ro.com", "appspot.com", "blogspot.ae", "blogspot.al", "blogspot.am", "blogspot.ba", "blogspot.be", "blogspot.bg", "blogspot.bj", "blogspot.ca", "blogspot.cf", "blogspot.ch", "blogspot.cl", "blogspot.co.at", "blogspot.co.id", "blogspot.co.il", "blogspot.co.ke", "blogspot.co.nz", "blogspot.co.uk", "blogspot.co.za", "blogspot.com", "blogspot.com.ar", "blogspot.com.au", "blogspot.com.br", "blogspot.com.by", "blogspot.com.co", "blogspot.com.cy", "blogspot.com.ee", "blogspot.com.eg", "blogspot.com.es", "blogspot.com.mt", "blogspot.com.ng", "blogspot.com.tr", "blogspot.com.uy", "blogspot.cv", "blogspot.cz", "blogspot.de", "blogspot.dk", "blogspot.fi", "blogspot.fr", "blogspot.gr", "blogspot.hk", "blogspot.hr", "blogspot.hu", "blogspot.ie", "blogspot.in", "blogspot.is", "blogspot.it", "blogspot.jp", "blogspot.kr", "blogspot.li", "blogspot.lt", "blogspot.lu", "blogspot.md", "blogspot.mk", "blogspot.mr", "blogspot.mx", "blogspot.my", "blogspot.nl", "blogspot.no", "blogspot.pe", "blogspot.pt", "blogspot.qa", "blogspot.re", "blogspot.ro", "blogspot.rs", "blogspot.ru", "blogspot.se", "blogspot.sg", "blogspot.si", "blogspot.sk", "blogspot.sn", "blogspot.td", "blogspot.tw", "blogspot.ug", "blogspot.vn", "codespot.com", "googleapis.com", "googlecode.com", "pagespeedmobilizer.com", "withgoogle.com", "withyoutube.com", "hashbang.sh", "herokuapp.com", "herokussl.com", "iki.fi", "biz.at", "info.at", "co.pl", "azurewebsites.net", "azure-mobile.net", "cloudapp.net", "bmoattachments.org", "4u.com", "ngrok.io", "nfshost.com", "nyc.mn", "nid.io", "operaunite.com", "outsystemscloud.com", "pagefrontapp.com", "art.pl", "gliwice.pl", "krakow.pl", "poznan.pl", "wroc.pl", "zakopane.pl", "pantheon.io", "gotpantheon.com", "priv.at", "qa2.com", "rackmaze.com", "rackmaze.net", "rhcloud.com", "sandcats.io", "biz.ua", "co.ua", "pp.ua", "sinaapp.com", "vipsinaapp.com", "1kapp.com", "synology.me", "diskstation.me", "i234.me", "myds.me", "dscloud.biz", "dscloud.me", "dscloud.mobi", "dsmynas.com", "dsmynas.net", "dsmynas.org", "familyds.com", "familyds.net", "familyds.org", "gda.pl", "gdansk.pl", "gdynia.pl", "med.pl", "sopot.pl", "hk.com", "hk.org", "ltd.hk", "inc.hk", "yolasite.com", "za.net", "za.org", } var nodeLabels = [...]string{ "aaa", "aarp", "abarth", "abb", "abbott", "abbvie", "abc", "able", "abogado", "abudhabi", "ac", "academy", "accenture", "accountant", "accountants", "aco", "active", "actor", "ad", "adac", "ads", "adult", "ae", "aeg", "aero", "aetna", "af", "afamilycompany", "afl", "africa", "africamagic", "ag", "agakhan", "agency", "ai", "aig", "aigo", "airbus", "airforce", "airtel", "akdn", "al", "alfaromeo", "alibaba", "alipay", "allfinanz", "allstate", "ally", "alsace", "alstom", "am", "americanexpress", "americanfamily", "amex", "amfam", "amica", "amsterdam", "analytics", "android", "anquan", "anz", "ao", "aol", "apartments", "app", "apple", "aq", "aquarelle", "ar", "aramco", "archi", "army", "arpa", "arte", "as", "asda", "asia", "associates", "at", "athleta", "attorney", "au", "auction", "audi", "audible", "audio", "auspost", "author", "auto", "autos", "avianca", "aw", "aws", "ax", "axa", "az", "azure", "ba", "baby", "baidu", "banamex", "bananarepublic", "band", "bank", "bar", "barcelona", "barclaycard", "barclays", "barefoot", "bargains", "baseball", "basketball", "bauhaus", "bayern", "bb", "bbc", "bbt", "bbva", "bcg", "bcn", "bd", "be", "beats", "beer", "bentley", "berlin", "best", "bestbuy", "bet", "bf", "bg", "bh", "bharti", "bi", "bible", "bid", "bike", "bing", "bingo", "bio", "biz", "bj", "black", "blackfriday", "blanco", "blockbuster", "blog", "bloomberg", "blue", "bm", "bms", "bmw", "bn", "bnl", "bnpparibas", "bo", "boats", "boehringer", "bofa", "bom", "bond", "boo", "book", "booking", "boots", "bosch", "bostik", "bot", "boutique", "br", "bradesco", "bridgestone", "broadway", "broker", "brother", "brussels", "bs", "bt", "budapest", "bugatti", "build", "builders", "business", "buy", "buzz", "bv", "bw", "by", "bz", "bzh", "ca", "cab", "cafe", "cal", "call", "calvinklein", "camera", "camp", "cancerresearch", "canon", "capetown", "capital", "capitalone", "car", "caravan", "cards", "care", "career", "careers", "cars", "cartier", "casa", "case", "caseih", "cash", "casino", "cat", "catering", "catholic", "cba", "cbn", "cbre", "cbs", "cc", "cd", "ceb", "center", "ceo", "cern", "cf", "cfa", "cfd", "cg", "ch", "chanel", "channel", "chase", "chat", "cheap", "chintai", "chloe", "christmas", "chrome", "chrysler", "church", "ci", "cipriani", "circle", "cisco", "citadel", "citi", "citic", "city", "cityeats", "ck", "cl", "claims", "cleaning", "click", "clinic", "clinique", "clothing", "cloud", "club", "clubmed", "cm", "cn", "co", "coach", "codes", "coffee", "college", "cologne", "com", "comcast", "commbank", "community", "company", "compare", "computer", "comsec", "condos", "construction", "consulting", "contact", "contractors", "cooking", "cookingchannel", "cool", "coop", "corsica", "country", "coupon", "coupons", "courses", "cr", "credit", "creditcard", "creditunion", "cricket", "crown", "crs", "cruises", "csc", "cu", "cuisinella", "cv", "cw", "cx", "cy", "cymru", "cyou", "cz", "dabur", "dad", "dance", "date", "dating", "datsun", "day", "dclk", "dds", "de", "deal", "dealer", "deals", "degree", "delivery", "dell", "deloitte", "delta", "democrat", "dental", "dentist", "desi", "design", "dev", "dhl", "diamonds", "diet", "digital", "direct", "directory", "discount", "discover", "dish", "diy", "dj", "dk", "dm", "dnp", "do", "docs", "dodge", "dog", "doha", "domains", "doosan", "dot", "download", "drive", "dstv", "dtv", "dubai", "duck", "dunlop", "duns", "dupont", "durban", "dvag", "dwg", "dz", "earth", "eat", "ec", "edeka", "edu", "education", "ee", "eg", "email", "emerck", "emerson", "energy", "engineer", "engineering", "enterprises", "epost", "epson", "equipment", "er", "ericsson", "erni", "es", "esq", "estate", "esurance", "et", "etisalat", "eu", "eurovision", "eus", "events", "everbank", "exchange", "expert", "exposed", "express", "extraspace", "fage", "fail", "fairwinds", "faith", "family", "fan", "fans", "farm", "farmers", "fashion", "fast", "fedex", "feedback", "ferrari", "ferrero", "fi", "fiat", "fidelity", "fido", "film", "final", "finance", "financial", "fire", "firestone", "firmdale", "fish", "fishing", "fit", "fitness", "fj", "fk", "flickr", "flights", "flir", "florist", "flowers", "flsmidth", "fly", "fm", "fo", "foo", "foodnetwork", "football", "ford", "forex", "forsale", "forum", "foundation", "fox", "fr", "fresenius", "frl", "frogans", "frontdoor", "frontier", "ftr", "fujitsu", "fujixerox", "fund", "furniture", "futbol", "fyi", "ga", "gal", "gallery", "gallo", "gallup", "game", "games", "gap", "garden", "gb", "gbiz", "gd", "gdn", "ge", "gea", "gent", "genting", "george", "gf", "gg", "ggee", "gh", "gi", "gift", "gifts", "gives", "giving", "gl", "glade", "glass", "gle", "global", "globo", "gm", "gmail", "gmo", "gmx", "gn", "godaddy", "gold", "goldpoint", "golf", "goo", "goodhands", "goodyear", "goog", "google", "gop", "got", "gotv", "gov", "gp", "gq", "gr", "grainger", "graphics", "gratis", "green", "gripe", "group", "gs", "gt", "gu", "guardian", "gucci", "guge", "guide", "guitars", "guru", "gw", "gy", "hamburg", "hangout", "haus", "hbo", "hdfc", "hdfcbank", "health", "healthcare", "help", "helsinki", "here", "hermes", "hgtv", "hiphop", "hisamitsu", "hitachi", "hiv", "hk", "hkt", "hm", "hn", "hockey", "holdings", "holiday", "homedepot", "homegoods", "homes", "homesense", "honda", "honeywell", "horse", "host", "hosting", "hot", "hoteles", "hotmail", "house", "how", "hr", "hsbc", "ht", "htc", "hu", "hughes", "hyatt", "hyundai", "ibm", "icbc", "ice", "icu", "id", "ie", "ieee", "ifm", "iinet", "ikano", "il", "im", "imamat", "imdb", "immo", "immobilien", "in", "industries", "infiniti", "info", "ing", "ink", "institute", "insurance", "insure", "int", "intel", "international", "intuit", "investments", "io", "ipiranga", "iq", "ir", "irish", "is", "iselect", "ismaili", "ist", "istanbul", "it", "itau", "itv", "iveco", "iwc", "jaguar", "java", "jcb", "jcp", "je", "jeep", "jetzt", "jewelry", "jio", "jlc", "jll", "jm", "jmp", "jnj", "jo", "jobs", "joburg", "jot", "joy", "jp", "jpmorgan", "jprs", "juegos", "juniper", "kaufen", "kddi", "ke", "kerryhotels", "kerrylogistics", "kerryproperties", "kfh", "kg", "kh", "ki", "kia", "kim", "kinder", "kindle", "kitchen", "kiwi", "km", "kn", "koeln", "komatsu", "kosher", "kp", "kpmg", "kpn", "kr", "krd", "kred", "kuokgroup", "kw", "ky", "kyknet", "kyoto", "kz", "la", "lacaixa", "ladbrokes", "lamborghini", "lamer", "lancaster", "lancia", "lancome", "land", "landrover", "lanxess", "lasalle", "lat", "latino", "latrobe", "law", "lawyer", "lb", "lc", "lds", "lease", "leclerc", "lefrak", "legal", "lego", "lexus", "lgbt", "li", "liaison", "lidl", "life", "lifeinsurance", "lifestyle", "lighting", "like", "lilly", "limited", "limo", "lincoln", "linde", "link", "lipsy", "live", "living", "lixil", "lk", "loan", "loans", "locker", "locus", "loft", "lol", "london", "lotte", "lotto", "love", "lpl", "lplfinancial", "lr", "ls", "lt", "ltd", "ltda", "lu", "lundbeck", "lupin", "luxe", "luxury", "lv", "ly", "ma", "macys", "madrid", "maif", "maison", "makeup", "man", "management", "mango", "market", "marketing", "markets", "marriott", "marshalls", "maserati", "mattel", "mba", "mc", "mcd", "mcdonalds", "mckinsey", "md", "me", "med", "media", "meet", "melbourne", "meme", "memorial", "men", "menu", "meo", "metlife", "mg", "mh", "miami", "microsoft", "mil", "mini", "mint", "mit", "mitsubishi", "mk", "ml", "mlb", "mls", "mm", "mma", "mn", "mnet", "mo", "mobi", "mobily", "moda", "moe", "moi", "mom", "monash", "money", "monster", "montblanc", "mopar", "mormon", "mortgage", "moscow", "moto", "motorcycles", "mov", "movie", "movistar", "mp", "mq", "mr", "ms", "msd", "mt", "mtn", "mtpc", "mtr", "mu", "multichoice", "museum", "mutual", "mutuelle", "mv", "mw", "mx", "my", "mz", "mzansimagic", "na", "nab", "nadex", "nagoya", "name", "naspers", "nationwide", "natura", "navy", "nba", "nc", "ne", "nec", "net", "netbank", "netflix", "network", "neustar", "new", "newholland", "news", "next", "nextdirect", "nexus", "nf", "nfl", "ng", "ngo", "nhk", "ni", "nico", "nike", "nikon", "ninja", "nissan", "nissay", "nl", "no", "nokia", "northwesternmutual", "norton", "now", "nowruz", "nowtv", "np", "nr", "nra", "nrw", "ntt", "nu", "nyc", "nz", "obi", "observer", "off", "office", "okinawa", "olayan", "olayangroup", "oldnavy", "ollo", "om", "omega", "one", "ong", "onl", "online", "onyourside", "ooo", "open", "oracle", "orange", "org", "organic", "orientexpress", "origins", "osaka", "otsuka", "ott", "ovh", "pa", "page", "pamperedchef", "panasonic", "panerai", "paris", "pars", "partners", "parts", "party", "passagens", "pay", "payu", "pccw", "pe", "pet", "pf", "pfizer", "pg", "ph", "pharmacy", "philips", "photo", "photography", "photos", "physio", "piaget", "pics", "pictet", "pictures", "pid", "pin", "ping", "pink", "pioneer", "pizza", "pk", "pl", "place", "play", "playstation", "plumbing", "plus", "pm", "pn", "pnc", "pohl", "poker", "politie", "porn", "post", "pr", "pramerica", "praxi", "press", "prime", "pro", "prod", "productions", "prof", "progressive", "promo", "properties", "property", "protection", "pru", "prudential", "ps", "pt", "pub", "pw", "pwc", "py", "qa", "qpon", "quebec", "quest", "qvc", "racing", "raid", "re", "read", "realestate", "realtor", "realty", "recipes", "red", "redstone", "redumbrella", "rehab", "reise", "reisen", "reit", "reliance", "ren", "rent", "rentals", "repair", "report", "republican", "rest", "restaurant", "review", "reviews", "rexroth", "rich", "richardli", "ricoh", "rightathome", "ril", "rio", "rip", "ro", "rocher", "rocks", "rodeo", "rogers", "room", "rs", "rsvp", "ru", "ruhr", "run", "rw", "rwe", "ryukyu", "sa", "saarland", "safe", "safety", "sakura", "sale", "salon", "samsclub", "samsung", "sandvik", "sandvikcoromant", "sanofi", "sap", "sapo", "sarl", "sas", "save", "saxo", "sb", "sbi", "sbs", "sc", "sca", "scb", "schaeffler", "schmidt", "scholarships", "school", "schule", "schwarz", "science", "scjohnson", "scor", "scot", "sd", "se", "seat", "secure", "security", "seek", "select", "sener", "services", "ses", "seven", "sew", "sex", "sexy", "sfr", "sg", "sh", "shangrila", "sharp", "shaw", "shell", "shia", "shiksha", "shoes", "shouji", "show", "showtime", "shriram", "si", "silk", "sina", "singles", "site", "sj", "sk", "ski", "skin", "sky", "skype", "sl", "sling", "sm", "smart", "smile", "sn", "sncf", "so", "soccer", "social", "softbank", "software", "sohu", "solar", "solutions", "song", "sony", "soy", "space", "spiegel", "spot", "spreadbetting", "sr", "srl", "srt", "st", "stada", "staples", "star", "starhub", "statebank", "statefarm", "statoil", "stc", "stcgroup", "stockholm", "storage", "store", "studio", "study", "style", "su", "sucks", "supersport", "supplies", "supply", "support", "surf", "surgery", "suzuki", "sv", "swatch", "swiftcover", "swiss", "sx", "sy", "sydney", "symantec", "systems", "sz", "tab", "taipei", "talk", "taobao", "target", "tatamotors", "tatar", "tattoo", "tax", "taxi", "tc", "tci", "td", "tdk", "team", "tech", "technology", "tel", "telecity", "telefonica", "temasek", "tennis", "teva", "tf", "tg", "th", "thd", "theater", "theatre", "theguardian", "tiaa", "tickets", "tienda", "tiffany", "tips", "tires", "tirol", "tj", "tjmaxx", "tjx", "tk", "tkmaxx", "tl", "tm", "tmall", "tn", "to", "today", "tokyo", "tools", "top", "toray", "toshiba", "total", "tours", "town", "toyota", "toys", "tp", "tr", "trade", "trading", "training", "travel", "travelchannel", "travelers", "travelersinsurance", "trust", "trv", "tt", "tube", "tui", "tunes", "tushu", "tv", "tvs", "tw", "tz", "ua", "ubank", "ubs", "uconnect", "ug", "uk", "unicom", "university", "uno", "uol", "ups", "us", "uy", "uz", "va", "vacations", "vana", "vanguard", "vc", "ve", "vegas", "ventures", "verisign", "versicherung", "vet", "vg", "vi", "viajes", "video", "vig", "viking", "villas", "vin", "vip", "virgin", "visa", "vision", "vista", "vistaprint", "viva", "vivo", "vlaanderen", "vn", "vodka", "volkswagen", "vote", "voting", "voto", "voyage", "vu", "vuelos", "wales", "walmart", "walter", "wang", "wanggou", "warman", "watch", "watches", "weather", "weatherchannel", "webcam", "weber", "website", "wed", "wedding", "weibo", "weir", "wf", "whoswho", "wien", "wiki", "williamhill", "win", "windows", "wine", "winners", "wme", "wolterskluwer", "woodside", "work", "works", "world", "wow", "ws", "wtc", "wtf", "xbox", "xerox", "xfinity", "xihuan", "xin", "xn--11b4c3d", "xn--1ck2e1b", "xn--1qqw23a", "xn--30rr7y", "xn--3bst00m", "xn--3ds443g", "xn--3e0b707e", "xn--3oq18vl8pn36a", "xn--3pxu8k", "xn--42c2d9a", "xn--45brj9c", "xn--45q11c", "xn--4gbrim", "xn--4gq48lf9j", "xn--54b7fta0cc", "xn--55qw42g", "xn--55qx5d", "xn--5su34j936bgsg", "xn--5tzm5g", "xn--6frz82g", "xn--6qq986b3xl", "xn--80adxhks", "xn--80ao21a", "xn--80aqecdr1a", "xn--80asehdb", "xn--80aswg", "xn--8y0a063a", "xn--90a3ac", "xn--90ais", "xn--9dbq2a", "xn--9et52u", "xn--9krt00a", "xn--b4w605ferd", "xn--bck1b9a5dre4c", "xn--c1avg", "xn--c2br7g", "xn--cck2b3b", "xn--cg4bki", "xn--clchc0ea0b2g2a9gcd", "xn--czr694b", "xn--czrs0t", "xn--czru2d", "xn--d1acj3b", "xn--d1alf", "xn--eckvdtc9d", "xn--efvy88h", "xn--estv75g", "xn--fct429k", "xn--fhbei", "xn--fiq228c5hs", "xn--fiq64b", "xn--fiqs8s", "xn--fiqz9s", "xn--fjq720a", "xn--flw351e", "xn--fpcrj9c3d", "xn--fzc2c9e2c", "xn--fzys8d69uvgm", "xn--g2xx48c", "xn--gckr3f0f", "xn--gecrj9c", "xn--gk3at1e", "xn--h2brj9c", "xn--hxt814e", "xn--i1b6b1a6a2e", "xn--imr513n", "xn--io0a7i", "xn--j1aef", "xn--j1amh", "xn--j6w193g", "xn--jlq61u9w7b", "xn--jvr189m", "xn--kcrx77d1x4a", "xn--kprw13d", "xn--kpry57d", "xn--kpu716f", "xn--kput3i", "xn--l1acc", "xn--lgbbat1ad8j", "xn--mgb2ddes", "xn--mgb9awbf", "xn--mgba3a3ejt", "xn--mgba3a4f16a", "xn--mgba3a4fra", "xn--mgba7c0bbn0a", "xn--mgbaakc7dvf", "xn--mgbaam7a8h", "xn--mgbab2bd", "xn--mgbai9a5eva00b", "xn--mgbai9azgqp6j", "xn--mgbayh7gpa", "xn--mgbb9fbpob", "xn--mgbbh1a71e", "xn--mgbc0a9azcg", "xn--mgbca7dzdo", "xn--mgberp4a5d4a87g", "xn--mgberp4a5d4ar", "xn--mgbi4ecexp", "xn--mgbpl2fh", "xn--mgbqly7c0a67fbc", "xn--mgbqly7cvafr", "xn--mgbt3dhd", "xn--mgbtf8fl", "xn--mgbtx2b", "xn--mgbx4cd0ab", "xn--mix082f", "xn--mix891f", "xn--mk1bu44c", "xn--mxtq1m", "xn--ngbc5azd", "xn--ngbe9e0a", "xn--nnx388a", "xn--node", "xn--nqv7f", "xn--nqv7fs00ema", "xn--nyqy26a", "xn--o3cw4h", "xn--ogbpf8fl", "xn--p1acf", "xn--p1ai", "xn--pbt977c", "xn--pgbs0dh", "xn--pssy2u", "xn--q9jyb4c", "xn--qcka1pmc", "xn--qxam", "xn--rhqv96g", "xn--rovu88b", "xn--s9brj9c", "xn--ses554g", "xn--t60b56a", "xn--tckwe", "xn--tiq49xqyj", "xn--unup4y", "xn--vermgensberater-ctb", "xn--vermgensberatung-pwb", "xn--vhquv", "xn--vuq861b", "xn--w4r85el8fhu5dnra", "xn--w4rs40l", "xn--wgbh1c", "xn--wgbl6a", "xn--xhq521b", "xn--xkc2al3hye2a", "xn--xkc2dl3a5ee0h", "xn--y9a3aq", "xn--yfro4i67o", "xn--ygbi2ammx", "xn--zfr164b", "xperia", "xxx", "xyz", "yachts", "yahoo", "yamaxun", "yandex", "ye", "yodobashi", "yoga", "yokohama", "you", "youtube", "yt", "yun", "za", "zappos", "zara", "zero", "zip", "zippo", "zm", "zone", "zuerich", "zw", "com", "edu", "gov", "mil", "net", "org", "nom", "ac", "blogspot", "co", "gov", "mil", "net", "org", "sch", "accident-investigation", "accident-prevention", "aerobatic", "aeroclub", "aerodrome", "agents", "air-surveillance", "air-traffic-control", "aircraft", "airline", "airport", "airtraffic", "ambulance", "amusement", "association", "author", "ballooning", "broker", "caa", "cargo", "catering", "certification", "championship", "charter", "civilaviation", "club", "conference", "consultant", "consulting", "control", "council", "crew", "design", "dgca", "educator", "emergency", "engine", "engineer", "entertainment", "equipment", "exchange", "express", "federation", "flight", "freight", "fuel", "gliding", "government", "groundhandling", "group", "hanggliding", "homebuilt", "insurance", "journal", "journalist", "leasing", "logistics", "magazine", "maintenance", "media", "microlight", "modelling", "navigation", "parachuting", "paragliding", "passenger-association", "pilot", "press", "production", "recreation", "repbody", "res", "research", "rotorcraft", "safety", "scientist", "services", "show", "skydiving", "software", "student", "trader", "trading", "trainer", "union", "workinggroup", "works", "com", "edu", "gov", "net", "org", "co", "com", "net", "nom", "org", "com", "net", "off", "org", "blogspot", "com", "edu", "gov", "mil", "net", "org", "blogspot", "co", "ed", "gv", "it", "og", "pb", "com", "edu", "gob", "gov", "int", "mil", "net", "org", "tur", "blogspot", "e164", "in-addr", "ip6", "iris", "uri", "urn", "gov", "ac", "biz", "co", "gv", "info", "or", "priv", "blogspot", "act", "asn", "com", "conf", "edu", "gov", "id", "info", "net", "nsw", "nt", "org", "oz", "qld", "sa", "tas", "vic", "wa", "blogspot", "act", "nsw", "nt", "qld", "sa", "tas", "vic", "wa", "qld", "sa", "tas", "vic", "wa", "com", "biz", "com", "edu", "gov", "info", "int", "mil", "name", "net", "org", "pp", "pro", "blogspot", "co", "com", "edu", "gov", "mil", "net", "org", "rs", "unbi", "unsa", "biz", "co", "com", "edu", "gov", "info", "net", "org", "store", "tv", "ac", "blogspot", "gov", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "blogspot", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "com", "edu", "gov", "net", "org", "co", "com", "edu", "or", "org", "dscloud", "dyndns", "for-better", "for-more", "for-some", "for-the", "selfip", "webhop", "asso", "barreau", "blogspot", "gouv", "com", "edu", "gov", "net", "org", "com", "edu", "gob", "gov", "int", "mil", "net", "org", "tv", "adm", "adv", "agr", "am", "arq", "art", "ato", "b", "bio", "blog", "bmd", "cim", "cng", "cnt", "com", "coop", "ecn", "eco", "edu", "emp", "eng", "esp", "etc", "eti", "far", "flog", "fm", "fnd", "fot", "fst", "g12", "ggf", "gov", "imb", "ind", "inf", "jor", "jus", "leg", "lel", "mat", "med", "mil", "mp", "mus", "net", "nom", "not", "ntr", "odo", "org", "ppg", "pro", "psc", "psi", "qsl", "radio", "rec", "slg", "srv", "taxi", "teo", "tmp", "trd", "tur", "tv", "vet", "vlog", "wiki", "zlg", "blogspot", "com", "edu", "gov", "net", "org", "com", "edu", "gov", "net", "org", "co", "org", "com", "gov", "mil", "of", "blogspot", "com", "edu", "gov", "net", "org", "za", "ab", "bc", "blogspot", "co", "gc", "mb", "nb", "nf", "nl", "ns", "nt", "nu", "on", "pe", "qc", "sk", "yk", "ftpaccess", "game-server", "myphotos", "scrapping", "gov", "blogspot", "blogspot", "ac", "asso", "co", "com", "ed", "edu", "go", "gouv", "int", "md", "net", "or", "org", "presse", "xn--aroport-bya", "www", "blogspot", "co", "gob", "gov", "mil", "co", "com", "gov", "net", "ac", "ah", "amazonaws", "bj", "com", "cq", "edu", "fj", "gd", "gov", "gs", "gx", "gz", "ha", "hb", "he", "hi", "hk", "hl", "hn", "jl", "js", "jx", "ln", "mil", "mo", "net", "nm", "nx", "org", "qh", "sc", "sd", "sh", "sn", "sx", "tj", "tw", "xj", "xn--55qx5d", "xn--io0a7i", "xn--od0alg", "xz", "yn", "zj", "compute", "cn-north-1", "amazonaws", "cn-north-1", "s3", "arts", "com", "edu", "firm", "gov", "info", "int", "mil", "net", "nom", "org", "rec", "web", "blogspot", "1kapp", "4u", "africa", "amazonaws", "appspot", "ar", "betainabox", "blogdns", "blogspot", "br", "cechire", "cloudcontrolapp", "cloudcontrolled", "cn", "co", "codespot", "de", "dnsalias", "dnsdojo", "doesntexist", "dontexist", "doomdns", "dreamhosters", "dsmynas", "dyn-o-saur", "dynalias", "dyndns-at-home", "dyndns-at-work", "dyndns-blog", "dyndns-free", "dyndns-home", "dyndns-ip", "dyndns-mail", "dyndns-office", "dyndns-pics", "dyndns-remote", "dyndns-server", "dyndns-web", "dyndns-wiki", "dyndns-work", "elasticbeanstalk", "est-a-la-maison", "est-a-la-masion", "est-le-patron", "est-mon-blogueur", "eu", "familyds", "firebaseapp", "flynnhub", "from-ak", "from-al", "from-ar", "from-ca", "from-ct", "from-dc", "from-de", "from-fl", "from-ga", "from-hi", "from-ia", "from-id", "from-il", "from-in", "from-ks", "from-ky", "from-ma", "from-md", "from-mi", "from-mn", "from-mo", "from-ms", "from-mt", "from-nc", "from-nd", "from-ne", "from-nh", "from-nj", "from-nm", "from-nv", "from-oh", "from-ok", "from-or", "from-pa", "from-pr", "from-ri", "from-sc", "from-sd", "from-tn", "from-tx", "from-ut", "from-va", "from-vt", "from-wa", "from-wi", "from-wv", "from-wy", "gb", "getmyip", "githubusercontent", "googleapis", "googlecode", "gotdns", "gotpantheon", "gr", "herokuapp", "herokussl", "hk", "hobby-site", "homelinux", "homeunix", "hu", "iamallama", "is-a-anarchist", "is-a-blogger", "is-a-bookkeeper", "is-a-bulls-fan", "is-a-caterer", "is-a-chef", "is-a-conservative", "is-a-cpa", "is-a-cubicle-slave", "is-a-democrat", "is-a-designer", "is-a-doctor", "is-a-financialadvisor", "is-a-geek", "is-a-green", "is-a-guru", "is-a-hard-worker", "is-a-hunter", "is-a-landscaper", "is-a-lawyer", "is-a-liberal", "is-a-libertarian", "is-a-llama", "is-a-musician", "is-a-nascarfan", "is-a-nurse", "is-a-painter", "is-a-personaltrainer", "is-a-photographer", "is-a-player", "is-a-republican", "is-a-rockstar", "is-a-socialist", "is-a-student", "is-a-teacher", "is-a-techie", "is-a-therapist", "is-an-accountant", "is-an-actor", "is-an-actress", "is-an-anarchist", "is-an-artist", "is-an-engineer", "is-an-entertainer", "is-certified", "is-gone", "is-into-anime", "is-into-cars", "is-into-cartoons", "is-into-games", "is-leet", "is-not-certified", "is-slick", "is-uberleet", "is-with-theband", "isa-geek", "isa-hockeynut", "issmarterthanyou", "jpn", "kr", "likes-pie", "likescandy", "mex", "neat-url", "nfshost", "no", "operaunite", "outsystemscloud", "pagefrontapp", "pagespeedmobilizer", "qa2", "qc", "rackmaze", "rhcloud", "ro", "ru", "sa", "saves-the-whales", "se", "selfip", "sells-for-less", "sells-for-u", "servebbs", "simple-url", "sinaapp", "space-to-rent", "teaches-yoga", "uk", "us", "uy", "vipsinaapp", "withgoogle", "withyoutube", "writesthisblog", "yolasite", "za", "compute", "compute-1", "elb", "eu-central-1", "s3", "s3-ap-northeast-1", "s3-ap-southeast-1", "s3-ap-southeast-2", "s3-eu-central-1", "s3-eu-west-1", "s3-external-1", "s3-external-2", "s3-fips-us-gov-west-1", "s3-sa-east-1", "s3-us-gov-west-1", "s3-us-west-1", "s3-us-west-2", "us-east-1", "ap-northeast-1", "ap-southeast-1", "ap-southeast-2", "eu-central-1", "eu-west-1", "sa-east-1", "us-gov-west-1", "us-west-1", "us-west-2", "z-1", "z-2", "s3", "ac", "co", "ed", "fi", "go", "or", "sa", "com", "edu", "gov", "inf", "net", "org", "blogspot", "com", "edu", "net", "org", "ath", "gov", "ac", "biz", "com", "ekloges", "gov", "ltd", "name", "net", "org", "parliament", "press", "pro", "tm", "blogspot", "blogspot", "blogspot", "com", "fuettertdasnetz", "isteingeek", "istmein", "lebtimnetz", "leitungsen", "traeumtgerade", "blogspot", "com", "edu", "gov", "net", "org", "art", "com", "edu", "gob", "gov", "mil", "net", "org", "sld", "web", "art", "asso", "com", "edu", "gov", "net", "org", "pol", "com", "edu", "fin", "gob", "gov", "info", "k12", "med", "mil", "net", "org", "pro", "aip", "com", "edu", "fie", "gov", "lib", "med", "org", "pri", "riik", "blogspot", "com", "edu", "eun", "gov", "mil", "name", "net", "org", "sci", "blogspot", "com", "edu", "gob", "nom", "org", "blogspot", "biz", "com", "edu", "gov", "info", "name", "net", "org", "aland", "blogspot", "iki", "aeroport", "assedic", "asso", "avocat", "avoues", "blogspot", "cci", "chambagri", "chirurgiens-dentistes", "com", "experts-comptables", "geometre-expert", "gouv", "greta", "huissier-justice", "medecin", "nom", "notaires", "pharmacien", "port", "prd", "presse", "tm", "veterinaire", "com", "edu", "gov", "mil", "net", "org", "pvt", "co", "net", "org", "com", "edu", "gov", "mil", "org", "com", "edu", "gov", "ltd", "mod", "org", "co", "com", "edu", "net", "org", "ac", "com", "edu", "gov", "net", "org", "asso", "com", "edu", "mobi", "net", "org", "blogspot", "com", "edu", "gov", "net", "org", "com", "edu", "gob", "ind", "mil", "net", "org", "co", "com", "net", "blogspot", "com", "edu", "gov", "idv", "inc", "ltd", "net", "org", "xn--55qx5d", "xn--ciqpn", "xn--gmq050i", "xn--gmqw5a", "xn--io0a7i", "xn--lcvr32d", "xn--mk0axi", "xn--mxtq1m", "xn--od0alg", "xn--od0aq3b", "xn--tn0ag", "xn--uc0atv", "xn--uc0ay4a", "xn--wcvs22d", "xn--zf0avx", "com", "edu", "gob", "mil", "net", "org", "blogspot", "com", "from", "iz", "name", "adult", "art", "asso", "com", "coop", "edu", "firm", "gouv", "info", "med", "net", "org", "perso", "pol", "pro", "rel", "shop", "2000", "agrar", "blogspot", "bolt", "casino", "city", "co", "erotica", "erotika", "film", "forum", "games", "hotel", "info", "ingatlan", "jogasz", "konyvelo", "lakas", "media", "news", "org", "priv", "reklam", "sex", "shop", "sport", "suli", "szex", "tm", "tozsde", "utazas", "video", "ac", "biz", "co", "desa", "go", "mil", "my", "net", "or", "sch", "web", "blogspot", "blogspot", "gov", "ac", "co", "gov", "idf", "k12", "muni", "net", "org", "blogspot", "ac", "co", "com", "net", "org", "tt", "tv", "ltd", "plc", "ac", "blogspot", "co", "edu", "firm", "gen", "gov", "ind", "mil", "net", "nic", "org", "res", "barrel-of-knowledge", "barrell-of-knowledge", "dyndns", "for-our", "groks-the", "groks-this", "here-for-more", "knowsitall", "selfip", "webhop", "eu", "com", "github", "ngrok", "nid", "pantheon", "sandcats", "com", "edu", "gov", "mil", "net", "org", "ac", "co", "gov", "id", "net", "org", "sch", "xn--mgba3a4f16a", "xn--mgba3a4fra", "blogspot", "com", "cupcake", "edu", "gov", "int", "net", "org", "abr", "abruzzo", "ag", "agrigento", "al", "alessandria", "alto-adige", "altoadige", "an", "ancona", "andria-barletta-trani", "andria-trani-barletta", "andriabarlettatrani", "andriatranibarletta", "ao", "aosta", "aosta-valley", "aostavalley", "aoste", "ap", "aq", "aquila", "ar", "arezzo", "ascoli-piceno", "ascolipiceno", "asti", "at", "av", "avellino", "ba", "balsan", "bari", "barletta-trani-andria", "barlettatraniandria", "bas", "basilicata", "belluno", "benevento", "bergamo", "bg", "bi", "biella", "bl", "blogspot", "bn", "bo", "bologna", "bolzano", "bozen", "br", "brescia", "brindisi", "bs", "bt", "bz", "ca", "cagliari", "cal", "calabria", "caltanissetta", "cam", "campania", "campidano-medio", "campidanomedio", "campobasso", "carbonia-iglesias", "carboniaiglesias", "carrara-massa", "carraramassa", "caserta", "catania", "catanzaro", "cb", "ce", "cesena-forli", "cesenaforli", "ch", "chieti", "ci", "cl", "cn", "co", "como", "cosenza", "cr", "cremona", "crotone", "cs", "ct", "cuneo", "cz", "dell-ogliastra", "dellogliastra", "edu", "emilia-romagna", "emiliaromagna", "emr", "en", "enna", "fc", "fe", "fermo", "ferrara", "fg", "fi", "firenze", "florence", "fm", "foggia", "forli-cesena", "forlicesena", "fr", "friuli-v-giulia", "friuli-ve-giulia", "friuli-vegiulia", "friuli-venezia-giulia", "friuli-veneziagiulia", "friuli-vgiulia", "friuliv-giulia", "friulive-giulia", "friulivegiulia", "friulivenezia-giulia", "friuliveneziagiulia", "friulivgiulia", "frosinone", "fvg", "ge", "genoa", "genova", "go", "gorizia", "gov", "gr", "grosseto", "iglesias-carbonia", "iglesiascarbonia", "im", "imperia", "is", "isernia", "kr", "la-spezia", "laquila", "laspezia", "latina", "laz", "lazio", "lc", "le", "lecce", "lecco", "li", "lig", "liguria", "livorno", "lo", "lodi", "lom", "lombardia", "lombardy", "lt", "lu", "lucania", "lucca", "macerata", "mantova", "mar", "marche", "massa-carrara", "massacarrara", "matera", "mb", "mc", "me", "medio-campidano", "mediocampidano", "messina", "mi", "milan", "milano", "mn", "mo", "modena", "mol", "molise", "monza", "monza-brianza", "monza-e-della-brianza", "monzabrianza", "monzaebrianza", "monzaedellabrianza", "ms", "mt", "na", "naples", "napoli", "no", "novara", "nu", "nuoro", "og", "ogliastra", "olbia-tempio", "olbiatempio", "or", "oristano", "ot", "pa", "padova", "padua", "palermo", "parma", "pavia", "pc", "pd", "pe", "perugia", "pesaro-urbino", "pesarourbino", "pescara", "pg", "pi", "piacenza", "piedmont", "piemonte", "pisa", "pistoia", "pmn", "pn", "po", "pordenone", "potenza", "pr", "prato", "pt", "pu", "pug", "puglia", "pv", "pz", "ra", "ragusa", "ravenna", "rc", "re", "reggio-calabria", "reggio-emilia", "reggiocalabria", "reggioemilia", "rg", "ri", "rieti", "rimini", "rm", "rn", "ro", "roma", "rome", "rovigo", "sa", "salerno", "sar", "sardegna", "sardinia", "sassari", "savona", "si", "sic", "sicilia", "sicily", "siena", "siracusa", "so", "sondrio", "sp", "sr", "ss", "suedtirol", "sv", "ta", "taa", "taranto", "te", "tempio-olbia", "tempioolbia", "teramo", "terni", "tn", "to", "torino", "tos", "toscana", "tp", "tr", "trani-andria-barletta", "trani-barletta-andria", "traniandriabarletta", "tranibarlettaandria", "trapani", "trentino", "trentino-a-adige", "trentino-aadige", "trentino-alto-adige", "trentino-altoadige", "trentino-s-tirol", "trentino-stirol", "trentino-sud-tirol", "trentino-sudtirol", "trentino-sued-tirol", "trentino-suedtirol", "trentinoa-adige", "trentinoaadige", "trentinoalto-adige", "trentinoaltoadige", "trentinos-tirol", "trentinostirol", "trentinosud-tirol", "trentinosudtirol", "trentinosued-tirol", "trentinosuedtirol", "trento", "treviso", "trieste", "ts", "turin", "tuscany", "tv", "ud", "udine", "umb", "umbria", "urbino-pesaro", "urbinopesaro", "va", "val-d-aosta", "val-daosta", "vald-aosta", "valdaosta", "valle-aosta", "valle-d-aosta", "valle-daosta", "valleaosta", "valled-aosta", "valledaosta", "vallee-aoste", "valleeaoste", "vao", "varese", "vb", "vc", "vda", "ve", "ven", "veneto", "venezia", "venice", "verbania", "vercelli", "verona", "vi", "vibo-valentia", "vibovalentia", "vicenza", "viterbo", "vr", "vs", "vt", "vv", "co", "net", "org", "com", "edu", "gov", "mil", "name", "net", "org", "sch", "ac", "ad", "aichi", "akita", "aomori", "blogspot", "chiba", "co", "ed", "ehime", "fukui", "fukuoka", "fukushima", "gifu", "go", "gr", "gunma", "hiroshima", "hokkaido", "hyogo", "ibaraki", "ishikawa", "iwate", "kagawa", "kagoshima", "kanagawa", "kawasaki", "kitakyushu", "kobe", "kochi", "kumamoto", "kyoto", "lg", "mie", "miyagi", "miyazaki", "nagano", "nagasaki", "nagoya", "nara", "ne", "niigata", "oita", "okayama", "okinawa", "or", "osaka", "saga", "saitama", "sapporo", "sendai", "shiga", "shimane", "shizuoka", "tochigi", "tokushima", "tokyo", "tottori", "toyama", "wakayama", "xn--0trq7p7nn", "xn--1ctwo", "xn--1lqs03n", "xn--1lqs71d", "xn--2m4a15e", "xn--32vp30h", "xn--4it168d", "xn--4it797k", "xn--4pvxs", "xn--5js045d", "xn--5rtp49c", "xn--5rtq34k", "xn--6btw5a", "xn--6orx2r", "xn--7t0a264c", "xn--8ltr62k", "xn--8pvr4u", "xn--c3s14m", "xn--d5qv7z876c", "xn--djrs72d6uy", "xn--djty4k", "xn--efvn9s", "xn--ehqz56n", "xn--elqq16h", "xn--f6qx53a", "xn--k7yn95e", "xn--kbrq7o", "xn--klt787d", "xn--kltp7d", "xn--kltx9a", "xn--klty5x", "xn--mkru45i", "xn--nit225k", "xn--ntso0iqx3a", "xn--ntsq17g", "xn--pssu33l", "xn--qqqt11m", "xn--rht27z", "xn--rht3d", "xn--rht61e", "xn--rny31h", "xn--tor131o", "xn--uist22h", "xn--uisz3g", "xn--uuwu58a", "xn--vgu402c", "xn--zbx025d", "yamagata", "yamaguchi", "yamanashi", "yokohama", "aisai", "ama", "anjo", "asuke", "chiryu", "chita", "fuso", "gamagori", "handa", "hazu", "hekinan", "higashiura", "ichinomiya", "inazawa", "inuyama", "isshiki", "iwakura", "kanie", "kariya", "kasugai", "kira", "kiyosu", "komaki", "konan", "kota", "mihama", "miyoshi", "nishio", "nisshin", "obu", "oguchi", "oharu", "okazaki", "owariasahi", "seto", "shikatsu", "shinshiro", "shitara", "tahara", "takahama", "tobishima", "toei", "togo", "tokai", "tokoname", "toyoake", "toyohashi", "toyokawa", "toyone", "toyota", "tsushima", "yatomi", "akita", "daisen", "fujisato", "gojome", "hachirogata", "happou", "higashinaruse", "honjo", "honjyo", "ikawa", "kamikoani", "kamioka", "katagami", "kazuno", "kitaakita", "kosaka", "kyowa", "misato", "mitane", "moriyoshi", "nikaho", "noshiro", "odate", "oga", "ogata", "semboku", "yokote", "yurihonjo", "aomori", "gonohe", "hachinohe", "hashikami", "hiranai", "hirosaki", "itayanagi", "kuroishi", "misawa", "mutsu", "nakadomari", "noheji", "oirase", "owani", "rokunohe", "sannohe", "shichinohe", "shingo", "takko", "towada", "tsugaru", "tsuruta", "abiko", "asahi", "chonan", "chosei", "choshi", "chuo", "funabashi", "futtsu", "hanamigawa", "ichihara", "ichikawa", "ichinomiya", "inzai", "isumi", "kamagaya", "kamogawa", "kashiwa", "katori", "katsuura", "kimitsu", "kisarazu", "kozaki", "kujukuri", "kyonan", "matsudo", "midori", "mihama", "minamiboso", "mobara", "mutsuzawa", "nagara", "nagareyama", "narashino", "narita", "noda", "oamishirasato", "omigawa", "onjuku", "otaki", "sakae", "sakura", "shimofusa", "shirako", "shiroi", "shisui", "sodegaura", "sosa", "tako", "tateyama", "togane", "tohnosho", "tomisato", "urayasu", "yachimata", "yachiyo", "yokaichiba", "yokoshibahikari", "yotsukaido", "ainan", "honai", "ikata", "imabari", "iyo", "kamijima", "kihoku", "kumakogen", "masaki", "matsuno", "matsuyama", "namikata", "niihama", "ozu", "saijo", "seiyo", "shikokuchuo", "tobe", "toon", "uchiko", "uwajima", "yawatahama", "echizen", "eiheiji", "fukui", "ikeda", "katsuyama", "mihama", "minamiechizen", "obama", "ohi", "ono", "sabae", "sakai", "takahama", "tsuruga", "wakasa", "ashiya", "buzen", "chikugo", "chikuho", "chikujo", "chikushino", "chikuzen", "chuo", "dazaifu", "fukuchi", "hakata", "higashi", "hirokawa", "hisayama", "iizuka", "inatsuki", "kaho", "kasuga", "kasuya", "kawara", "keisen", "koga", "kurate", "kurogi", "kurume", "minami", "miyako", "miyama", "miyawaka", "mizumaki", "munakata", "nakagawa", "nakama", "nishi", "nogata", "ogori", "okagaki", "okawa", "oki", "omuta", "onga", "onojo", "oto", "saigawa", "sasaguri", "shingu", "shinyoshitomi", "shonai", "soeda", "sue", "tachiarai", "tagawa", "takata", "toho", "toyotsu", "tsuiki", "ukiha", "umi", "usui", "yamada", "yame", "yanagawa", "yukuhashi", "aizubange", "aizumisato", "aizuwakamatsu", "asakawa", "bandai", "date", "fukushima", "furudono", "futaba", "hanawa", "higashi", "hirata", "hirono", "iitate", "inawashiro", "ishikawa", "iwaki", "izumizaki", "kagamiishi", "kaneyama", "kawamata", "kitakata", "kitashiobara", "koori", "koriyama", "kunimi", "miharu", "mishima", "namie", "nango", "nishiaizu", "nishigo", "okuma", "omotego", "ono", "otama", "samegawa", "shimogo", "shirakawa", "showa", "soma", "sukagawa", "taishin", "tamakawa", "tanagura", "tenei", "yabuki", "yamato", "yamatsuri", "yanaizu", "yugawa", "anpachi", "ena", "gifu", "ginan", "godo", "gujo", "hashima", "hichiso", "hida", "higashishirakawa", "ibigawa", "ikeda", "kakamigahara", "kani", "kasahara", "kasamatsu", "kawaue", "kitagata", "mino", "minokamo", "mitake", "mizunami", "motosu", "nakatsugawa", "ogaki", "sakahogi", "seki", "sekigahara", "shirakawa", "tajimi", "takayama", "tarui", "toki", "tomika", "wanouchi", "yamagata", "yaotsu", "yoro", "annaka", "chiyoda", "fujioka", "higashiagatsuma", "isesaki", "itakura", "kanna", "kanra", "katashina", "kawaba", "kiryu", "kusatsu", "maebashi", "meiwa", "midori", "minakami", "naganohara", "nakanojo", "nanmoku", "numata", "oizumi", "ora", "ota", "shibukawa", "shimonita", "shinto", "showa", "takasaki", "takayama", "tamamura", "tatebayashi", "tomioka", "tsukiyono", "tsumagoi", "ueno", "yoshioka", "asaminami", "daiwa", "etajima", "fuchu", "fukuyama", "hatsukaichi", "higashihiroshima", "hongo", "jinsekikogen", "kaita", "kui", "kumano", "kure", "mihara", "miyoshi", "naka", "onomichi", "osakikamijima", "otake", "saka", "sera", "seranishi", "shinichi", "shobara", "takehara", "abashiri", "abira", "aibetsu", "akabira", "akkeshi", "asahikawa", "ashibetsu", "ashoro", "assabu", "atsuma", "bibai", "biei", "bifuka", "bihoro", "biratori", "chippubetsu", "chitose", "date", "ebetsu", "embetsu", "eniwa", "erimo", "esan", "esashi", "fukagawa", "fukushima", "furano", "furubira", "haboro", "hakodate", "hamatonbetsu", "hidaka", "higashikagura", "higashikawa", "hiroo", "hokuryu", "hokuto", "honbetsu", "horokanai", "horonobe", "ikeda", "imakane", "ishikari", "iwamizawa", "iwanai", "kamifurano", "kamikawa", "kamishihoro", "kamisunagawa", "kamoenai", "kayabe", "kembuchi", "kikonai", "kimobetsu", "kitahiroshima", "kitami", "kiyosato", "koshimizu", "kunneppu", "kuriyama", "kuromatsunai", "kushiro", "kutchan", "kyowa", "mashike", "matsumae", "mikasa", "minamifurano", "mombetsu", "moseushi", "mukawa", "muroran", "naie", "nakagawa", "nakasatsunai", "nakatombetsu", "nanae", "nanporo", "nayoro", "nemuro", "niikappu", "niki", "nishiokoppe", "noboribetsu", "numata", "obihiro", "obira", "oketo", "okoppe", "otaru", "otobe", "otofuke", "otoineppu", "oumu", "ozora", "pippu", "rankoshi", "rebun", "rikubetsu", "rishiri", "rishirifuji", "saroma", "sarufutsu", "shakotan", "shari", "shibecha", "shibetsu", "shikabe", "shikaoi", "shimamaki", "shimizu", "shimokawa", "shinshinotsu", "shintoku", "shiranuka", "shiraoi", "shiriuchi", "sobetsu", "sunagawa", "taiki", "takasu", "takikawa", "takinoue", "teshikaga", "tobetsu", "tohma", "tomakomai", "tomari", "toya", "toyako", "toyotomi", "toyoura", "tsubetsu", "tsukigata", "urakawa", "urausu", "uryu", "utashinai", "wakkanai", "wassamu", "yakumo", "yoichi", "aioi", "akashi", "ako", "amagasaki", "aogaki", "asago", "ashiya", "awaji", "fukusaki", "goshiki", "harima", "himeji", "ichikawa", "inagawa", "itami", "kakogawa", "kamigori", "kamikawa", "kasai", "kasuga", "kawanishi", "miki", "minamiawaji", "nishinomiya", "nishiwaki", "ono", "sanda", "sannan", "sasayama", "sayo", "shingu", "shinonsen", "shiso", "sumoto", "taishi", "taka", "takarazuka", "takasago", "takino", "tamba", "tatsuno", "toyooka", "yabu", "yashiro", "yoka", "yokawa", "ami", "asahi", "bando", "chikusei", "daigo", "fujishiro", "hitachi", "hitachinaka", "hitachiomiya", "hitachiota", "ibaraki", "ina", "inashiki", "itako", "iwama", "joso", "kamisu", "kasama", "kashima", "kasumigaura", "koga", "miho", "mito", "moriya", "naka", "namegata", "oarai", "ogawa", "omitama", "ryugasaki", "sakai", "sakuragawa", "shimodate", "shimotsuma", "shirosato", "sowa", "suifu", "takahagi", "tamatsukuri", "tokai", "tomobe", "tone", "toride", "tsuchiura", "tsukuba", "uchihara", "ushiku", "yachiyo", "yamagata", "yawara", "yuki", "anamizu", "hakui", "hakusan", "kaga", "kahoku", "kanazawa", "kawakita", "komatsu", "nakanoto", "nanao", "nomi", "nonoichi", "noto", "shika", "suzu", "tsubata", "tsurugi", "uchinada", "wajima", "fudai", "fujisawa", "hanamaki", "hiraizumi", "hirono", "ichinohe", "ichinoseki", "iwaizumi", "iwate", "joboji", "kamaishi", "kanegasaki", "karumai", "kawai", "kitakami", "kuji", "kunohe", "kuzumaki", "miyako", "mizusawa", "morioka", "ninohe", "noda", "ofunato", "oshu", "otsuchi", "rikuzentakata", "shiwa", "shizukuishi", "sumita", "tanohata", "tono", "yahaba", "yamada", "ayagawa", "higashikagawa", "kanonji", "kotohira", "manno", "marugame", "mitoyo", "naoshima", "sanuki", "tadotsu", "takamatsu", "tonosho", "uchinomi", "utazu", "zentsuji", "akune", "amami", "hioki", "isa", "isen", "izumi", "kagoshima", "kanoya", "kawanabe", "kinko", "kouyama", "makurazaki", "matsumoto", "minamitane", "nakatane", "nishinoomote", "satsumasendai", "soo", "tarumizu", "yusui", "aikawa", "atsugi", "ayase", "chigasaki", "ebina", "fujisawa", "hadano", "hakone", "hiratsuka", "isehara", "kaisei", "kamakura", "kiyokawa", "matsuda", "minamiashigara", "miura", "nakai", "ninomiya", "odawara", "oi", "oiso", "sagamihara", "samukawa", "tsukui", "yamakita", "yamato", "yokosuka", "yugawara", "zama", "zushi", "city", "city", "city", "aki", "geisei", "hidaka", "higashitsuno", "ino", "kagami", "kami", "kitagawa", "kochi", "mihara", "motoyama", "muroto", "nahari", "nakamura", "nankoku", "nishitosa", "niyodogawa", "ochi", "okawa", "otoyo", "otsuki", "sakawa", "sukumo", "susaki", "tosa", "tosashimizu", "toyo", "tsuno", "umaji", "yasuda", "yusuhara", "amakusa", "arao", "aso", "choyo", "gyokuto", "hitoyoshi", "kamiamakusa", "kashima", "kikuchi", "kosa", "kumamoto", "mashiki", "mifune", "minamata", "minamioguni", "nagasu", "nishihara", "oguni", "ozu", "sumoto", "takamori", "uki", "uto", "yamaga", "yamato", "yatsushiro", "ayabe", "fukuchiyama", "higashiyama", "ide", "ine", "joyo", "kameoka", "kamo", "kita", "kizu", "kumiyama", "kyotamba", "kyotanabe", "kyotango", "maizuru", "minami", "minamiyamashiro", "miyazu", "muko", "nagaokakyo", "nakagyo", "nantan", "oyamazaki", "sakyo", "seika", "tanabe", "uji", "ujitawara", "wazuka", "yamashina", "yawata", "asahi", "inabe", "ise", "kameyama", "kawagoe", "kiho", "kisosaki", "kiwa", "komono", "kumano", "kuwana", "matsusaka", "meiwa", "mihama", "minamiise", "misugi", "miyama", "nabari", "shima", "suzuka", "tado", "taiki", "taki", "tamaki", "toba", "tsu", "udono", "ureshino", "watarai", "yokkaichi", "furukawa", "higashimatsushima", "ishinomaki", "iwanuma", "kakuda", "kami", "kawasaki", "kesennuma", "marumori", "matsushima", "minamisanriku", "misato", "murata", "natori", "ogawara", "ohira", "onagawa", "osaki", "rifu", "semine", "shibata", "shichikashuku", "shikama", "shiogama", "shiroishi", "tagajo", "taiwa", "tome", "tomiya", "wakuya", "watari", "yamamoto", "zao", "aya", "ebino", "gokase", "hyuga", "kadogawa", "kawaminami", "kijo", "kitagawa", "kitakata", "kitaura", "kobayashi", "kunitomi", "kushima", "mimata", "miyakonojo", "miyazaki", "morotsuka", "nichinan", "nishimera", "nobeoka", "saito", "shiiba", "shintomi", "takaharu", "takanabe", "takazaki", "tsuno", "achi", "agematsu", "anan", "aoki", "asahi", "azumino", "chikuhoku", "chikuma", "chino", "fujimi", "hakuba", "hara", "hiraya", "iida", "iijima", "iiyama", "iizuna", "ikeda", "ikusaka", "ina", "karuizawa", "kawakami", "kiso", "kisofukushima", "kitaaiki", "komagane", "komoro", "matsukawa", "matsumoto", "miasa", "minamiaiki", "minamimaki", "minamiminowa", "minowa", "miyada", "miyota", "mochizuki", "nagano", "nagawa", "nagiso", "nakagawa", "nakano", "nozawaonsen", "obuse", "ogawa", "okaya", "omachi", "omi", "ookuwa", "ooshika", "otaki", "otari", "sakae", "sakaki", "saku", "sakuho", "shimosuwa", "shinanomachi", "shiojiri", "suwa", "suzaka", "takagi", "takamori", "takayama", "tateshina", "tatsuno", "togakushi", "togura", "tomi", "ueda", "wada", "yamagata", "yamanouchi", "yasaka", "yasuoka", "chijiwa", "futsu", "goto", "hasami", "hirado", "iki", "isahaya", "kawatana", "kuchinotsu", "matsuura", "nagasaki", "obama", "omura", "oseto", "saikai", "sasebo", "seihi", "shimabara", "shinkamigoto", "togitsu", "tsushima", "unzen", "city", "ando", "gose", "heguri", "higashiyoshino", "ikaruga", "ikoma", "kamikitayama", "kanmaki", "kashiba", "kashihara", "katsuragi", "kawai", "kawakami", "kawanishi", "koryo", "kurotaki", "mitsue", "miyake", "nara", "nosegawa", "oji", "ouda", "oyodo", "sakurai", "sango", "shimoichi", "shimokitayama", "shinjo", "soni", "takatori", "tawaramoto", "tenkawa", "tenri", "uda", "yamatokoriyama", "yamatotakada", "yamazoe", "yoshino", "aga", "agano", "gosen", "itoigawa", "izumozaki", "joetsu", "kamo", "kariwa", "kashiwazaki", "minamiuonuma", "mitsuke", "muika", "murakami", "myoko", "nagaoka", "niigata", "ojiya", "omi", "sado", "sanjo", "seiro", "seirou", "sekikawa", "shibata", "tagami", "tainai", "tochio", "tokamachi", "tsubame", "tsunan", "uonuma", "yahiko", "yoita", "yuzawa", "beppu", "bungoono", "bungotakada", "hasama", "hiji", "himeshima", "hita", "kamitsue", "kokonoe", "kuju", "kunisaki", "kusu", "oita", "saiki", "taketa", "tsukumi", "usa", "usuki", "yufu", "akaiwa", "asakuchi", "bizen", "hayashima", "ibara", "kagamino", "kasaoka", "kibichuo", "kumenan", "kurashiki", "maniwa", "misaki", "nagi", "niimi", "nishiawakura", "okayama", "satosho", "setouchi", "shinjo", "shoo", "soja", "takahashi", "tamano", "tsuyama", "wake", "yakage", "aguni", "ginowan", "ginoza", "gushikami", "haebaru", "higashi", "hirara", "iheya", "ishigaki", "ishikawa", "itoman", "izena", "kadena", "kin", "kitadaito", "kitanakagusuku", "kumejima", "kunigami", "minamidaito", "motobu", "nago", "naha", "nakagusuku", "nakijin", "nanjo", "nishihara", "ogimi", "okinawa", "onna", "shimoji", "taketomi", "tarama", "tokashiki", "tomigusuku", "tonaki", "urasoe", "uruma", "yaese", "yomitan", "yonabaru", "yonaguni", "zamami", "abeno", "chihayaakasaka", "chuo", "daito", "fujiidera", "habikino", "hannan", "higashiosaka", "higashisumiyoshi", "higashiyodogawa", "hirakata", "ibaraki", "ikeda", "izumi", "izumiotsu", "izumisano", "kadoma", "kaizuka", "kanan", "kashiwara", "katano", "kawachinagano", "kishiwada", "kita", "kumatori", "matsubara", "minato", "minoh", "misaki", "moriguchi", "neyagawa", "nishi", "nose", "osakasayama", "sakai", "sayama", "sennan", "settsu", "shijonawate", "shimamoto", "suita", "tadaoka", "taishi", "tajiri", "takaishi", "takatsuki", "tondabayashi", "toyonaka", "toyono", "yao", "ariake", "arita", "fukudomi", "genkai", "hamatama", "hizen", "imari", "kamimine", "kanzaki", "karatsu", "kashima", "kitagata", "kitahata", "kiyama", "kouhoku", "kyuragi", "nishiarita", "ogi", "omachi", "ouchi", "saga", "shiroishi", "taku", "tara", "tosu", "yoshinogari", "arakawa", "asaka", "chichibu", "fujimi", "fujimino", "fukaya", "hanno", "hanyu", "hasuda", "hatogaya", "hatoyama", "hidaka", "higashichichibu", "higashimatsuyama", "honjo", "ina", "iruma", "iwatsuki", "kamiizumi", "kamikawa", "kamisato", "kasukabe", "kawagoe", "kawaguchi", "kawajima", "kazo", "kitamoto", "koshigaya", "kounosu", "kuki", "kumagaya", "matsubushi", "minano", "misato", "miyashiro", "miyoshi", "moroyama", "nagatoro", "namegawa", "niiza", "ogano", "ogawa", "ogose", "okegawa", "omiya", "otaki", "ranzan", "ryokami", "saitama", "sakado", "satte", "sayama", "shiki", "shiraoka", "soka", "sugito", "toda", "tokigawa", "tokorozawa", "tsurugashima", "urawa", "warabi", "yashio", "yokoze", "yono", "yorii", "yoshida", "yoshikawa", "yoshimi", "city", "city", "aisho", "gamo", "higashiomi", "hikone", "koka", "konan", "kosei", "koto", "kusatsu", "maibara", "moriyama", "nagahama", "nishiazai", "notogawa", "omihachiman", "otsu", "ritto", "ryuoh", "takashima", "takatsuki", "torahime", "toyosato", "yasu", "akagi", "ama", "gotsu", "hamada", "higashiizumo", "hikawa", "hikimi", "izumo", "kakinoki", "masuda", "matsue", "misato", "nishinoshima", "ohda", "okinoshima", "okuizumo", "shimane", "tamayu", "tsuwano", "unnan", "yakumo", "yasugi", "yatsuka", "arai", "atami", "fuji", "fujieda", "fujikawa", "fujinomiya", "fukuroi", "gotemba", "haibara", "hamamatsu", "higashiizu", "ito", "iwata", "izu", "izunokuni", "kakegawa", "kannami", "kawanehon", "kawazu", "kikugawa", "kosai", "makinohara", "matsuzaki", "minamiizu", "mishima", "morimachi", "nishiizu", "numazu", "omaezaki", "shimada", "shimizu", "shimoda", "shizuoka", "susono", "yaizu", "yoshida", "ashikaga", "bato", "haga", "ichikai", "iwafune", "kaminokawa", "kanuma", "karasuyama", "kuroiso", "mashiko", "mibu", "moka", "motegi", "nasu", "nasushiobara", "nikko", "nishikata", "nogi", "ohira", "ohtawara", "oyama", "sakura", "sano", "shimotsuke", "shioya", "takanezawa", "tochigi", "tsuga", "ujiie", "utsunomiya", "yaita", "aizumi", "anan", "ichiba", "itano", "kainan", "komatsushima", "matsushige", "mima", "minami", "miyoshi", "mugi", "nakagawa", "naruto", "sanagochi", "shishikui", "tokushima", "wajiki", "adachi", "akiruno", "akishima", "aogashima", "arakawa", "bunkyo", "chiyoda", "chofu", "chuo", "edogawa", "fuchu", "fussa", "hachijo", "hachioji", "hamura", "higashikurume", "higashimurayama", "higashiyamato", "hino", "hinode", "hinohara", "inagi", "itabashi", "katsushika", "kita", "kiyose", "kodaira", "koganei", "kokubunji", "komae", "koto", "kouzushima", "kunitachi", "machida", "meguro", "minato", "mitaka", "mizuho", "musashimurayama", "musashino", "nakano", "nerima", "ogasawara", "okutama", "ome", "oshima", "ota", "setagaya", "shibuya", "shinagawa", "shinjuku", "suginami", "sumida", "tachikawa", "taito", "tama", "toshima", "chizu", "hino", "kawahara", "koge", "kotoura", "misasa", "nanbu", "nichinan", "sakaiminato", "tottori", "wakasa", "yazu", "yonago", "asahi", "fuchu", "fukumitsu", "funahashi", "himi", "imizu", "inami", "johana", "kamiichi", "kurobe", "nakaniikawa", "namerikawa", "nanto", "nyuzen", "oyabe", "taira", "takaoka", "tateyama", "toga", "tonami", "toyama", "unazuki", "uozu", "yamada", "arida", "aridagawa", "gobo", "hashimoto", "hidaka", "hirogawa", "inami", "iwade", "kainan", "kamitonda", "katsuragi", "kimino", "kinokawa", "kitayama", "koya", "koza", "kozagawa", "kudoyama", "kushimoto", "mihama", "misato", "nachikatsuura", "shingu", "shirahama", "taiji", "tanabe", "wakayama", "yuasa", "yura", "asahi", "funagata", "higashine", "iide", "kahoku", "kaminoyama", "kaneyama", "kawanishi", "mamurogawa", "mikawa", "murayama", "nagai", "nakayama", "nanyo", "nishikawa", "obanazawa", "oe", "oguni", "ohkura", "oishida", "sagae", "sakata", "sakegawa", "shinjo", "shirataka", "shonai", "takahata", "tendo", "tozawa", "tsuruoka", "yamagata", "yamanobe", "yonezawa", "yuza", "abu", "hagi", "hikari", "hofu", "iwakuni", "kudamatsu", "mitou", "nagato", "oshima", "shimonoseki", "shunan", "tabuse", "tokuyama", "toyota", "ube", "yuu", "chuo", "doshi", "fuefuki", "fujikawa", "fujikawaguchiko", "fujiyoshida", "hayakawa", "hokuto", "ichikawamisato", "kai", "kofu", "koshu", "kosuge", "minami-alps", "minobu", "nakamichi", "nanbu", "narusawa", "nirasaki", "nishikatsura", "oshino", "otsuki", "showa", "tabayama", "tsuru", "uenohara", "yamanakako", "yamanashi", "city", "co", "blogspot", "com", "edu", "gov", "mil", "net", "org", "biz", "com", "edu", "gov", "info", "net", "org", "ass", "asso", "com", "coop", "edu", "gouv", "gov", "medecin", "mil", "nom", "notaires", "org", "pharmaciens", "prd", "presse", "tm", "veterinaire", "edu", "gov", "net", "org", "com", "edu", "gov", "org", "rep", "tra", "ac", "blogspot", "busan", "chungbuk", "chungnam", "co", "daegu", "daejeon", "es", "gangwon", "go", "gwangju", "gyeongbuk", "gyeonggi", "gyeongnam", "hs", "incheon", "jeju", "jeonbuk", "jeonnam", "kg", "mil", "ms", "ne", "or", "pe", "re", "sc", "seoul", "ulsan", "com", "edu", "gov", "net", "org", "com", "edu", "gov", "mil", "net", "org", "c", "com", "edu", "gov", "info", "int", "net", "org", "per", "com", "edu", "gov", "net", "org", "co", "com", "edu", "gov", "net", "org", "blogspot", "ac", "assn", "com", "edu", "gov", "grp", "hotel", "int", "ltd", "net", "ngo", "org", "sch", "soc", "web", "com", "edu", "gov", "net", "org", "co", "org", "blogspot", "gov", "blogspot", "asn", "com", "conf", "edu", "gov", "id", "mil", "net", "org", "com", "edu", "gov", "id", "med", "net", "org", "plc", "sch", "ac", "co", "gov", "net", "org", "press", "asso", "tm", "blogspot", "ac", "co", "diskstation", "dscloud", "edu", "gov", "i234", "its", "myds", "net", "org", "priv", "synology", "co", "com", "edu", "gov", "mil", "nom", "org", "prd", "tm", "blogspot", "com", "edu", "gov", "inf", "name", "net", "org", "com", "edu", "gouv", "gov", "net", "org", "presse", "edu", "gov", "nyc", "org", "com", "edu", "gov", "net", "org", "dscloud", "blogspot", "gov", "com", "edu", "gov", "net", "org", "com", "edu", "net", "org", "blogspot", "ac", "co", "com", "gov", "net", "or", "org", "academy", "agriculture", "air", "airguard", "alabama", "alaska", "amber", "ambulance", "american", "americana", "americanantiques", "americanart", "amsterdam", "and", "annefrank", "anthro", "anthropology", "antiques", "aquarium", "arboretum", "archaeological", "archaeology", "architecture", "art", "artanddesign", "artcenter", "artdeco", "arteducation", "artgallery", "arts", "artsandcrafts", "asmatart", "assassination", "assisi", "association", "astronomy", "atlanta", "austin", "australia", "automotive", "aviation", "axis", "badajoz", "baghdad", "bahn", "bale", "baltimore", "barcelona", "baseball", "basel", "baths", "bauern", "beauxarts", "beeldengeluid", "bellevue", "bergbau", "berkeley", "berlin", "bern", "bible", "bilbao", "bill", "birdart", "birthplace", "bonn", "boston", "botanical", "botanicalgarden", "botanicgarden", "botany", "brandywinevalley", "brasil", "bristol", "british", "britishcolumbia", "broadcast", "brunel", "brussel", "brussels", "bruxelles", "building", "burghof", "bus", "bushey", "cadaques", "california", "cambridge", "can", "canada", "capebreton", "carrier", "cartoonart", "casadelamoneda", "castle", "castres", "celtic", "center", "chattanooga", "cheltenham", "chesapeakebay", "chicago", "children", "childrens", "childrensgarden", "chiropractic", "chocolate", "christiansburg", "cincinnati", "cinema", "circus", "civilisation", "civilization", "civilwar", "clinton", "clock", "coal", "coastaldefence", "cody", "coldwar", "collection", "colonialwilliamsburg", "coloradoplateau", "columbia", "columbus", "communication", "communications", "community", "computer", "computerhistory", "contemporary", "contemporaryart", "convent", "copenhagen", "corporation", "corvette", "costume", "countryestate", "county", "crafts", "cranbrook", "creation", "cultural", "culturalcenter", "culture", "cyber", "cymru", "dali", "dallas", "database", "ddr", "decorativearts", "delaware", "delmenhorst", "denmark", "depot", "design", "detroit", "dinosaur", "discovery", "dolls", "donostia", "durham", "eastafrica", "eastcoast", "education", "educational", "egyptian", "eisenbahn", "elburg", "elvendrell", "embroidery", "encyclopedic", "england", "entomology", "environment", "environmentalconservation", "epilepsy", "essex", "estate", "ethnology", "exeter", "exhibition", "family", "farm", "farmequipment", "farmers", "farmstead", "field", "figueres", "filatelia", "film", "fineart", "finearts", "finland", "flanders", "florida", "force", "fortmissoula", "fortworth", "foundation", "francaise", "frankfurt", "franziskaner", "freemasonry", "freiburg", "fribourg", "frog", "fundacio", "furniture", "gallery", "garden", "gateway", "geelvinck", "gemological", "geology", "georgia", "giessen", "glas", "glass", "gorge", "grandrapids", "graz", "guernsey", "halloffame", "hamburg", "handson", "harvestcelebration", "hawaii", "health", "heimatunduhren", "hellas", "helsinki", "hembygdsforbund", "heritage", "histoire", "historical", "historicalsociety", "historichouses", "historisch", "historisches", "history", "historyofscience", "horology", "house", "humanities", "illustration", "imageandsound", "indian", "indiana", "indianapolis", "indianmarket", "intelligence", "interactive", "iraq", "iron", "isleofman", "jamison", "jefferson", "jerusalem", "jewelry", "jewish", "jewishart", "jfk", "journalism", "judaica", "judygarland", "juedisches", "juif", "karate", "karikatur", "kids", "koebenhavn", "koeln", "kunst", "kunstsammlung", "kunstunddesign", "labor", "labour", "lajolla", "lancashire", "landes", "lans", "larsson", "lewismiller", "lincoln", "linz", "living", "livinghistory", "localhistory", "london", "losangeles", "louvre", "loyalist", "lucerne", "luxembourg", "luzern", "mad", "madrid", "mallorca", "manchester", "mansion", "mansions", "manx", "marburg", "maritime", "maritimo", "maryland", "marylhurst", "media", "medical", "medizinhistorisches", "meeres", "memorial", "mesaverde", "michigan", "midatlantic", "military", "mill", "miners", "mining", "minnesota", "missile", "missoula", "modern", "moma", "money", "monmouth", "monticello", "montreal", "moscow", "motorcycle", "muenchen", "muenster", "mulhouse", "muncie", "museet", "museumcenter", "museumvereniging", "music", "national", "nationalfirearms", "nationalheritage", "nativeamerican", "naturalhistory", "naturalhistorymuseum", "naturalsciences", "nature", "naturhistorisches", "natuurwetenschappen", "naumburg", "naval", "nebraska", "neues", "newhampshire", "newjersey", "newmexico", "newport", "newspaper", "newyork", "niepce", "norfolk", "north", "nrw", "nuernberg", "nuremberg", "nyc", "nyny", "oceanographic", "oceanographique", "omaha", "online", "ontario", "openair", "oregon", "oregontrail", "otago", "oxford", "pacific", "paderborn", "palace", "paleo", "palmsprings", "panama", "paris", "pasadena", "pharmacy", "philadelphia", "philadelphiaarea", "philately", "phoenix", "photography", "pilots", "pittsburgh", "planetarium", "plantation", "plants", "plaza", "portal", "portland", "portlligat", "posts-and-telecommunications", "preservation", "presidio", "press", "project", "public", "pubol", "quebec", "railroad", "railway", "research", "resistance", "riodejaneiro", "rochester", "rockart", "roma", "russia", "saintlouis", "salem", "salvadordali", "salzburg", "sandiego", "sanfrancisco", "santabarbara", "santacruz", "santafe", "saskatchewan", "satx", "savannahga", "schlesisches", "schoenbrunn", "schokoladen", "school", "schweiz", "science", "science-fiction", "scienceandhistory", "scienceandindustry", "sciencecenter", "sciencecenters", "sciencehistory", "sciences", "sciencesnaturelles", "scotland", "seaport", "settlement", "settlers", "shell", "sherbrooke", "sibenik", "silk", "ski", "skole", "society", "sologne", "soundandvision", "southcarolina", "southwest", "space", "spy", "square", "stadt", "stalbans", "starnberg", "state", "stateofdelaware", "station", "steam", "steiermark", "stjohn", "stockholm", "stpetersburg", "stuttgart", "suisse", "surgeonshall", "surrey", "svizzera", "sweden", "sydney", "tank", "tcm", "technology", "telekommunikation", "television", "texas", "textile", "theater", "time", "timekeeping", "topology", "torino", "touch", "town", "transport", "tree", "trolley", "trust", "trustee", "uhren", "ulm", "undersea", "university", "usa", "usantiques", "usarts", "uscountryestate", "usculture", "usdecorativearts", "usgarden", "ushistory", "ushuaia", "uslivinghistory", "utah", "uvic", "valley", "vantaa", "versailles", "viking", "village", "virginia", "virtual", "virtuel", "vlaanderen", "volkenkunde", "wales", "wallonie", "war", "washingtondc", "watch-and-clock", "watchandclock", "western", "westfalen", "whaling", "wildlife", "williamsburg", "windmill", "workshop", "xn--9dbhblg6di", "xn--comunicaes-v6a2o", "xn--correios-e-telecomunicaes-ghc29a", "xn--h1aegh", "xn--lns-qla", "york", "yorkshire", "yosemite", "youth", "zoological", "zoology", "aero", "biz", "com", "coop", "edu", "gov", "info", "int", "mil", "museum", "name", "net", "org", "pro", "ac", "biz", "co", "com", "coop", "edu", "gov", "int", "museum", "net", "org", "blogspot", "com", "edu", "gob", "net", "org", "blogspot", "com", "edu", "gov", "mil", "name", "net", "org", "teledata", "ca", "cc", "co", "com", "dr", "in", "info", "mobi", "mx", "name", "or", "org", "pro", "school", "tv", "us", "ws", "her", "his", "forgot", "forgot", "asso", "at-band-camp", "azure-mobile", "azurewebsites", "blogdns", "broke-it", "buyshouses", "cdn77", "cdn77-ssl", "cloudapp", "cloudfront", "dnsalias", "dnsdojo", "does-it", "dontexist", "dsmynas", "dynalias", "dynathome", "endofinternet", "familyds", "fastly", "from-az", "from-co", "from-la", "from-ny", "gb", "gets-it", "ham-radio-op", "homeftp", "homeip", "homelinux", "homeunix", "hu", "in", "in-the-band", "is-a-chef", "is-a-geek", "isa-geek", "jp", "kicks-ass", "office-on-the", "podzone", "rackmaze", "scrapper-site", "se", "selfip", "sells-it", "servebbs", "serveftp", "thruhere", "uk", "webhop", "za", "r", "prod", "ssl", "a", "global", "a", "b", "global", "arts", "com", "firm", "info", "net", "other", "per", "rec", "store", "web", "com", "edu", "gov", "mil", "mobi", "name", "net", "org", "sch", "blogspot", "ac", "biz", "co", "com", "edu", "gob", "in", "info", "int", "mil", "net", "nom", "org", "web", "blogspot", "bv", "co", "aa", "aarborte", "aejrie", "afjord", "agdenes", "ah", "akershus", "aknoluokta", "akrehamn", "al", "alaheadju", "alesund", "algard", "alstahaug", "alta", "alvdal", "amli", "amot", "andasuolo", "andebu", "andoy", "ardal", "aremark", "arendal", "arna", "aseral", "asker", "askim", "askoy", "askvoll", "asnes", "audnedaln", "aukra", "aure", "aurland", "aurskog-holand", "austevoll", "austrheim", "averoy", "badaddja", "bahcavuotna", "bahccavuotna", "baidar", "bajddar", "balat", "balestrand", "ballangen", "balsfjord", "bamble", "bardu", "barum", "batsfjord", "bearalvahki", "beardu", "beiarn", "berg", "bergen", "berlevag", "bievat", "bindal", "birkenes", "bjarkoy", "bjerkreim", "bjugn", "blogspot", "bodo", "bokn", "bomlo", "bremanger", "bronnoy", "bronnoysund", "brumunddal", "bryne", "bu", "budejju", "buskerud", "bygland", "bykle", "cahcesuolo", "co", "davvenjarga", "davvesiida", "deatnu", "dep", "dielddanuorri", "divtasvuodna", "divttasvuotna", "donna", "dovre", "drammen", "drangedal", "drobak", "dyroy", "egersund", "eid", "eidfjord", "eidsberg", "eidskog", "eidsvoll", "eigersund", "elverum", "enebakk", "engerdal", "etne", "etnedal", "evenassi", "evenes", "evje-og-hornnes", "farsund", "fauske", "fedje", "fet", "fetsund", "fhs", "finnoy", "fitjar", "fjaler", "fjell", "fla", "flakstad", "flatanger", "flekkefjord", "flesberg", "flora", "floro", "fm", "folkebibl", "folldal", "forde", "forsand", "fosnes", "frana", "fredrikstad", "frei", "frogn", "froland", "frosta", "froya", "fuoisku", "fuossko", "fusa", "fylkesbibl", "fyresdal", "gaivuotna", "galsa", "gamvik", "gangaviika", "gaular", "gausdal", "giehtavuoatna", "gildeskal", "giske", "gjemnes", "gjerdrum", "gjerstad", "gjesdal", "gjovik", "gloppen", "gol", "gran", "grane", "granvin", "gratangen", "grimstad", "grong", "grue", "gulen", "guovdageaidnu", "ha", "habmer", "hadsel", "hagebostad", "halden", "halsa", "hamar", "hamaroy", "hammarfeasta", "hammerfest", "hapmir", "haram", "hareid", "harstad", "hasvik", "hattfjelldal", "haugesund", "hedmark", "hemne", "hemnes", "hemsedal", "herad", "hitra", "hjartdal", "hjelmeland", "hl", "hm", "hobol", "hof", "hokksund", "hol", "hole", "holmestrand", "holtalen", "honefoss", "hordaland", "hornindal", "horten", "hoyanger", "hoylandet", "hurdal", "hurum", "hvaler", "hyllestad", "ibestad", "idrett", "inderoy", "iveland", "ivgu", "jan-mayen", "jessheim", "jevnaker", "jolster", "jondal", "jorpeland", "kafjord", "karasjohka", "karasjok", "karlsoy", "karmoy", "kautokeino", "kirkenes", "klabu", "klepp", "kommune", "kongsberg", "kongsvinger", "kopervik", "kraanghke", "kragero", "kristiansand", "kristiansund", "krodsherad", "krokstadelva", "kvafjord", "kvalsund", "kvam", "kvanangen", "kvinesdal", "kvinnherad", "kviteseid", "kvitsoy", "laakesvuemie", "lahppi", "langevag", "lardal", "larvik", "lavagis", "lavangen", "leangaviika", "lebesby", "leikanger", "leirfjord", "leirvik", "leka", "leksvik", "lenvik", "lerdal", "lesja", "levanger", "lier", "lierne", "lillehammer", "lillesand", "lindas", "lindesnes", "loabat", "lodingen", "lom", "loppa", "lorenskog", "loten", "lund", "lunner", "luroy", "luster", "lyngdal", "lyngen", "malatvuopmi", "malselv", "malvik", "mandal", "marker", "marnardal", "masfjorden", "masoy", "matta-varjjat", "meland", "meldal", "melhus", "meloy", "meraker", "midsund", "midtre-gauldal", "mil", "mjondalen", "mo-i-rana", "moareke", "modalen", "modum", "molde", "more-og-romsdal", "mosjoen", "moskenes", "moss", "mosvik", "mr", "muosat", "museum", "naamesjevuemie", "namdalseid", "namsos", "namsskogan", "nannestad", "naroy", "narviika", "narvik", "naustdal", "navuotna", "nedre-eiker", "nesna", "nesodden", "nesoddtangen", "nesseby", "nesset", "nissedal", "nittedal", "nl", "nord-aurdal", "nord-fron", "nord-odal", "norddal", "nordkapp", "nordland", "nordre-land", "nordreisa", "nore-og-uvdal", "notodden", "notteroy", "nt", "odda", "of", "oksnes", "ol", "omasvuotna", "oppdal", "oppegard", "orkanger", "orkdal", "orland", "orskog", "orsta", "osen", "oslo", "osoyro", "osteroy", "ostfold", "ostre-toten", "overhalla", "ovre-eiker", "oyer", "oygarden", "oystre-slidre", "porsanger", "porsangu", "porsgrunn", "priv", "rade", "radoy", "rahkkeravju", "raholt", "raisa", "rakkestad", "ralingen", "rana", "randaberg", "rauma", "rendalen", "rennebu", "rennesoy", "rindal", "ringebu", "ringerike", "ringsaker", "risor", "rissa", "rl", "roan", "rodoy", "rollag", "romsa", "romskog", "roros", "rost", "royken", "royrvik", "ruovat", "rygge", "salangen", "salat", "saltdal", "samnanger", "sandefjord", "sandnes", "sandnessjoen", "sandoy", "sarpsborg", "sauda", "sauherad", "sel", "selbu", "selje", "seljord", "sf", "siellak", "sigdal", "siljan", "sirdal", "skanit", "skanland", "skaun", "skedsmo", "skedsmokorset", "ski", "skien", "skierva", "skiptvet", "skjak", "skjervoy", "skodje", "slattum", "smola", "snaase", "snasa", "snillfjord", "snoasa", "sogndal", "sogne", "sokndal", "sola", "solund", "somna", "sondre-land", "songdalen", "sor-aurdal", "sor-fron", "sor-odal", "sor-varanger", "sorfold", "sorreisa", "sortland", "sorum", "spjelkavik", "spydeberg", "st", "stange", "stat", "stathelle", "stavanger", "stavern", "steigen", "steinkjer", "stjordal", "stjordalshalsen", "stokke", "stor-elvdal", "stord", "stordal", "storfjord", "strand", "stranda", "stryn", "sula", "suldal", "sund", "sunndal", "surnadal", "svalbard", "sveio", "svelvik", "sykkylven", "tana", "tananger", "telemark", "time", "tingvoll", "tinn", "tjeldsund", "tjome", "tm", "tokke", "tolga", "tonsberg", "torsken", "tr", "trana", "tranby", "tranoy", "troandin", "trogstad", "tromsa", "tromso", "trondheim", "trysil", "tvedestrand", "tydal", "tynset", "tysfjord", "tysnes", "tysvar", "ullensaker", "ullensvang", "ulvik", "unjarga", "utsira", "va", "vaapste", "vadso", "vaga", "vagan", "vagsoy", "vaksdal", "valle", "vang", "vanylven", "vardo", "varggat", "varoy", "vefsn", "vega", "vegarshei", "vennesla", "verdal", "verran", "vestby", "vestfold", "vestnes", "vestre-slidre", "vestre-toten", "vestvagoy", "vevelstad", "vf", "vgs", "vik", "vikna", "vindafjord", "voagat", "volda", "voss", "vossevangen", "xn--andy-ira", "xn--asky-ira", "xn--aurskog-hland-jnb", "xn--avery-yua", "xn--bdddj-mrabd", "xn--bearalvhki-y4a", "xn--berlevg-jxa", "xn--bhcavuotna-s4a", "xn--bhccavuotna-k7a", "xn--bidr-5nac", "xn--bievt-0qa", "xn--bjarky-fya", "xn--bjddar-pta", "xn--blt-elab", "xn--bmlo-gra", "xn--bod-2na", "xn--brnny-wuac", "xn--brnnysund-m8ac", "xn--brum-voa", "xn--btsfjord-9za", "xn--davvenjrga-y4a", "xn--dnna-gra", "xn--drbak-wua", "xn--dyry-ira", "xn--eveni-0qa01ga", "xn--finny-yua", "xn--fjord-lra", "xn--fl-zia", "xn--flor-jra", "xn--frde-gra", "xn--frna-woa", "xn--frya-hra", "xn--ggaviika-8ya47h", "xn--gildeskl-g0a", "xn--givuotna-8ya", "xn--gjvik-wua", "xn--gls-elac", "xn--h-2fa", "xn--hbmer-xqa", "xn--hcesuolo-7ya35b", "xn--hgebostad-g3a", "xn--hmmrfeasta-s4ac", "xn--hnefoss-q1a", "xn--hobl-ira", "xn--holtlen-hxa", "xn--hpmir-xqa", "xn--hyanger-q1a", "xn--hylandet-54a", "xn--indery-fya", "xn--jlster-bya", "xn--jrpeland-54a", "xn--karmy-yua", "xn--kfjord-iua", "xn--klbu-woa", "xn--koluokta-7ya57h", "xn--krager-gya", "xn--kranghke-b0a", "xn--krdsherad-m8a", "xn--krehamn-dxa", "xn--krjohka-hwab49j", "xn--ksnes-uua", "xn--kvfjord-nxa", "xn--kvitsy-fya", "xn--kvnangen-k0a", "xn--l-1fa", "xn--laheadju-7ya", "xn--langevg-jxa", "xn--ldingen-q1a", "xn--leagaviika-52b", "xn--lesund-hua", "xn--lgrd-poac", "xn--lhppi-xqa", "xn--linds-pra", "xn--loabt-0qa", "xn--lrdal-sra", "xn--lrenskog-54a", "xn--lt-liac", "xn--lten-gra", "xn--lury-ira", "xn--mely-ira", "xn--merker-kua", "xn--mjndalen-64a", "xn--mlatvuopmi-s4a", "xn--mli-tla", "xn--mlselv-iua", "xn--moreke-jua", "xn--mosjen-eya", "xn--mot-tla", "xn--mre-og-romsdal-qqb", "xn--msy-ula0h", "xn--mtta-vrjjat-k7af", "xn--muost-0qa", "xn--nmesjevuemie-tcba", "xn--nry-yla5g", "xn--nttery-byae", "xn--nvuotna-hwa", "xn--oppegrd-ixa", "xn--ostery-fya", "xn--osyro-wua", "xn--porsgu-sta26f", "xn--rady-ira", "xn--rdal-poa", "xn--rde-ula", "xn--rdy-0nab", "xn--rennesy-v1a", "xn--rhkkervju-01af", "xn--rholt-mra", "xn--risa-5na", "xn--risr-ira", "xn--rland-uua", "xn--rlingen-mxa", "xn--rmskog-bya", "xn--rros-gra", "xn--rskog-uua", "xn--rst-0na", "xn--rsta-fra", "xn--ryken-vua", "xn--ryrvik-bya", "xn--s-1fa", "xn--sandnessjen-ogb", "xn--sandy-yua", "xn--seral-lra", "xn--sgne-gra", "xn--skierv-uta", "xn--skjervy-v1a", "xn--skjk-soa", "xn--sknit-yqa", "xn--sknland-fxa", "xn--slat-5na", "xn--slt-elab", "xn--smla-hra", "xn--smna-gra", "xn--snase-nra", "xn--sndre-land-0cb", "xn--snes-poa", "xn--snsa-roa", "xn--sr-aurdal-l8a", "xn--sr-fron-q1a", "xn--sr-odal-q1a", "xn--sr-varanger-ggb", "xn--srfold-bya", "xn--srreisa-q1a", "xn--srum-gra", "xn--stfold-9xa", "xn--stjrdal-s1a", "xn--stjrdalshalsen-sqb", "xn--stre-toten-zcb", "xn--tjme-hra", "xn--tnsberg-q1a", "xn--trany-yua", "xn--trgstad-r1a", "xn--trna-woa", "xn--troms-zua", "xn--tysvr-vra", "xn--unjrga-rta", "xn--vads-jra", "xn--vard-jra", "xn--vegrshei-c0a", "xn--vestvgy-ixa6o", "xn--vg-yiab", "xn--vgan-qoa", "xn--vgsy-qoa0j", "xn--vre-eiker-k8a", "xn--vrggt-xqad", "xn--vry-yla5g", "xn--yer-zna", "xn--ygarden-p1a", "xn--ystre-slidre-ujb", "gs", "gs", "nes", "gs", "nes", "gs", "os", "valer", "xn--vler-qoa", "gs", "gs", "os", "gs", "heroy", "sande", "gs", "gs", "bo", "heroy", "xn--b-5ga", "xn--hery-ira", "gs", "gs", "gs", "gs", "valer", "gs", "gs", "gs", "gs", "bo", "xn--b-5ga", "gs", "gs", "gs", "sande", "gs", "sande", "xn--hery-ira", "xn--vler-qoa", "biz", "com", "edu", "gov", "info", "net", "org", "merseine", "mine", "shacknet", "ac", "co", "cri", "geek", "gen", "govt", "health", "iwi", "kiwi", "maori", "mil", "net", "org", "parliament", "school", "xn--mori-qsa", "blogspot", "co", "com", "edu", "gov", "med", "museum", "net", "org", "pro", "ae", "blogdns", "blogsite", "bmoattachments", "boldlygoingnowhere", "cdn77", "cdn77-secure", "dnsalias", "dnsdojo", "doesntexist", "dontexist", "doomdns", "dsmynas", "duckdns", "dvrdns", "dynalias", "dyndns", "endofinternet", "endoftheinternet", "eu", "familyds", "from-me", "game-host", "gotdns", "hk", "hobby-site", "homedns", "homeftp", "homelinux", "homeunix", "is-a-bruinsfan", "is-a-candidate", "is-a-celticsfan", "is-a-chef", "is-a-geek", "is-a-knight", "is-a-linux-user", "is-a-patsfan", "is-a-soxfan", "is-found", "is-lost", "is-saved", "is-very-bad", "is-very-evil", "is-very-good", "is-very-nice", "is-very-sweet", "isa-geek", "kicks-ass", "misconfused", "podzone", "readmyblog", "selfip", "sellsyourhome", "servebbs", "serveftp", "servegame", "stuff-4-sale", "us", "webhop", "za", "c", "rsc", "origin", "ssl", "go", "home", "al", "asso", "at", "au", "be", "bg", "ca", "cd", "ch", "cn", "cy", "cz", "de", "dk", "edu", "ee", "es", "fi", "fr", "gr", "hr", "hu", "ie", "il", "in", "int", "is", "it", "jp", "kr", "lt", "lu", "lv", "mc", "me", "mk", "mt", "my", "net", "ng", "nl", "no", "nz", "paris", "pl", "pt", "q-a", "ro", "ru", "se", "si", "sk", "tr", "uk", "us", "abo", "ac", "com", "edu", "gob", "ing", "med", "net", "nom", "org", "sld", "blogspot", "com", "edu", "gob", "mil", "net", "nom", "org", "com", "edu", "org", "com", "edu", "gov", "i", "mil", "net", "ngo", "org", "biz", "com", "edu", "fam", "gob", "gok", "gon", "gop", "gos", "gov", "info", "net", "org", "web", "agro", "aid", "art", "atm", "augustow", "auto", "babia-gora", "bedzin", "beskidy", "bialowieza", "bialystok", "bielawa", "bieszczady", "biz", "boleslawiec", "bydgoszcz", "bytom", "cieszyn", "co", "com", "czeladz", "czest", "dlugoleka", "edu", "elblag", "elk", "gda", "gdansk", "gdynia", "gliwice", "glogow", "gmina", "gniezno", "gorlice", "gov", "grajewo", "gsm", "ilawa", "info", "jaworzno", "jelenia-gora", "jgora", "kalisz", "karpacz", "kartuzy", "kaszuby", "katowice", "kazimierz-dolny", "kepno", "ketrzyn", "klodzko", "kobierzyce", "kolobrzeg", "konin", "konskowola", "krakow", "kutno", "lapy", "lebork", "legnica", "lezajsk", "limanowa", "lomza", "lowicz", "lubin", "lukow", "mail", "malbork", "malopolska", "mazowsze", "mazury", "med", "media", "miasta", "mielec", "mielno", "mil", "mragowo", "naklo", "net", "nieruchomosci", "nom", "nowaruda", "nysa", "olawa", "olecko", "olkusz", "olsztyn", "opoczno", "opole", "org", "ostroda", "ostroleka", "ostrowiec", "ostrowwlkp", "pc", "pila", "pisz", "podhale", "podlasie", "polkowice", "pomorskie", "pomorze", "powiat", "poznan", "priv", "prochowice", "pruszkow", "przeworsk", "pulawy", "radom", "rawa-maz", "realestate", "rel", "rybnik", "rzeszow", "sanok", "sejny", "sex", "shop", "sklep", "skoczow", "slask", "slupsk", "sopot", "sos", "sosnowiec", "stalowa-wola", "starachowice", "stargard", "suwalki", "swidnica", "swiebodzin", "swinoujscie", "szczecin", "szczytno", "szkola", "targi", "tarnobrzeg", "tgory", "tm", "tourism", "travel", "turek", "turystyka", "tychy", "ustka", "walbrzych", "warmia", "warszawa", "waw", "wegrow", "wielun", "wlocl", "wloclawek", "wodzislaw", "wolomin", "wroc", "wroclaw", "zachpomor", "zagan", "zakopane", "zarow", "zgora", "zgorzelec", "ap", "griw", "ic", "is", "kmpsp", "konsulat", "kppsp", "kwp", "kwpsp", "mup", "mw", "oirm", "oum", "pa", "pinb", "piw", "po", "psp", "psse", "pup", "rzgw", "sa", "sdn", "sko", "so", "sr", "starostwo", "ug", "ugim", "um", "umig", "upow", "uppo", "us", "uw", "uzs", "wif", "wiih", "winb", "wios", "witd", "wiw", "wsa", "wskr", "wuoz", "wzmiuw", "zp", "co", "edu", "gov", "net", "org", "ac", "biz", "com", "edu", "est", "gov", "info", "isla", "name", "net", "org", "pro", "prof", "aca", "bar", "cpa", "eng", "jur", "law", "med", "com", "edu", "gov", "net", "org", "plo", "sec", "blogspot", "com", "edu", "gov", "int", "net", "nome", "org", "publ", "belau", "co", "ed", "go", "ne", "or", "com", "coop", "edu", "gov", "mil", "net", "org", "blogspot", "com", "edu", "gov", "mil", "name", "net", "org", "sch", "asso", "blogspot", "com", "nom", "arts", "blogspot", "com", "firm", "info", "nom", "nt", "org", "rec", "store", "tm", "www", "ac", "blogspot", "co", "edu", "gov", "in", "org", "ac", "adygeya", "altai", "amur", "amursk", "arkhangelsk", "astrakhan", "baikal", "bashkiria", "belgorod", "bir", "blogspot", "bryansk", "buryatia", "cbg", "chel", "chelyabinsk", "chita", "chukotka", "chuvashia", "cmw", "com", "dagestan", "dudinka", "e-burg", "edu", "fareast", "gov", "grozny", "int", "irkutsk", "ivanovo", "izhevsk", "jamal", "jar", "joshkar-ola", "k-uralsk", "kalmykia", "kaluga", "kamchatka", "karelia", "kazan", "kchr", "kemerovo", "khabarovsk", "khakassia", "khv", "kirov", "kms", "koenig", "komi", "kostroma", "krasnoyarsk", "kuban", "kurgan", "kursk", "kustanai", "kuzbass", "lipetsk", "magadan", "mari", "mari-el", "marine", "mil", "mordovia", "msk", "murmansk", "mytis", "nakhodka", "nalchik", "net", "nkz", "nnov", "norilsk", "nov", "novosibirsk", "nsk", "omsk", "orenburg", "org", "oryol", "oskol", "palana", "penza", "perm", "pp", "ptz", "pyatigorsk", "rnd", "rubtsovsk", "ryazan", "sakhalin", "samara", "saratov", "simbirsk", "smolensk", "snz", "spb", "stavropol", "stv", "surgut", "syzran", "tambov", "tatarstan", "test", "tom", "tomsk", "tsaritsyn", "tsk", "tula", "tuva", "tver", "tyumen", "udm", "udmurtia", "ulan-ude", "vdonsk", "vladikavkaz", "vladimir", "vladivostok", "volgograd", "vologda", "voronezh", "vrn", "vyatka", "yakutia", "yamal", "yaroslavl", "yekaterinburg", "yuzhno-sakhalinsk", "zgrad", "ac", "co", "com", "edu", "gouv", "gov", "int", "mil", "net", "com", "edu", "gov", "med", "net", "org", "pub", "sch", "com", "edu", "gov", "net", "org", "com", "edu", "gov", "net", "org", "com", "edu", "gov", "info", "med", "net", "org", "tv", "a", "ac", "b", "bd", "blogspot", "brand", "c", "com", "d", "e", "f", "fh", "fhsk", "fhv", "g", "h", "i", "k", "komforb", "kommunalforbund", "komvux", "l", "lanbib", "m", "n", "naturbruksgymn", "o", "org", "p", "parti", "pp", "press", "r", "s", "t", "tm", "u", "w", "x", "y", "z", "blogspot", "com", "edu", "gov", "net", "org", "per", "com", "gov", "hashbang", "mil", "net", "org", "platform", "blogspot", "blogspot", "com", "edu", "gov", "net", "org", "art", "blogspot", "com", "edu", "gouv", "org", "perso", "univ", "com", "net", "org", "co", "com", "consulado", "edu", "embaixada", "gov", "mil", "net", "org", "principe", "saotome", "store", "adygeya", "arkhangelsk", "balashov", "bashkiria", "bryansk", "dagestan", "grozny", "ivanovo", "kalmykia", "kaluga", "karelia", "khakassia", "krasnodar", "kurgan", "lenug", "mordovia", "msk", "murmansk", "nalchik", "nov", "obninsk", "penza", "pokrovsk", "sochi", "spb", "togliatti", "troitsk", "tula", "tuva", "vladikavkaz", "vladimir", "vologda", "com", "edu", "gob", "org", "red", "gov", "com", "edu", "gov", "mil", "net", "org", "ac", "co", "org", "blogspot", "ac", "co", "go", "in", "mi", "net", "or", "ac", "biz", "co", "com", "edu", "go", "gov", "int", "mil", "name", "net", "nic", "org", "test", "web", "gov", "co", "com", "edu", "gov", "mil", "net", "nom", "org", "agrinet", "com", "defense", "edunet", "ens", "fin", "gov", "ind", "info", "intl", "mincom", "nat", "net", "org", "perso", "rnrt", "rns", "rnu", "tourism", "turen", "com", "edu", "gov", "mil", "net", "org", "av", "bbs", "bel", "biz", "com", "dr", "edu", "gen", "gov", "info", "k12", "kep", "mil", "name", "nc", "net", "org", "pol", "tel", "tv", "web", "blogspot", "gov", "aero", "biz", "co", "com", "coop", "edu", "gov", "info", "int", "jobs", "mobi", "museum", "name", "net", "org", "pro", "travel", "better-than", "dyndns", "on-the-web", "worse-than", "blogspot", "club", "com", "ebiz", "edu", "game", "gov", "idv", "mil", "net", "org", "xn--czrw28b", "xn--uc0atv", "xn--zf0ao64a", "ac", "co", "go", "hotel", "info", "me", "mil", "mobi", "ne", "or", "sc", "tv", "biz", "cherkassy", "cherkasy", "chernigov", "chernihiv", "chernivtsi", "chernovtsy", "ck", "cn", "co", "com", "cr", "crimea", "cv", "dn", "dnepropetrovsk", "dnipropetrovsk", "dominic", "donetsk", "dp", "edu", "gov", "if", "in", "ivano-frankivsk", "kh", "kharkiv", "kharkov", "kherson", "khmelnitskiy", "khmelnytskyi", "kiev", "kirovograd", "km", "kr", "krym", "ks", "kv", "kyiv", "lg", "lt", "lugansk", "lutsk", "lv", "lviv", "mk", "mykolaiv", "net", "nikolaev", "od", "odesa", "odessa", "org", "pl", "poltava", "pp", "rivne", "rovno", "rv", "sb", "sebastopol", "sevastopol", "sm", "sumy", "te", "ternopil", "uz", "uzhgorod", "vinnica", "vinnytsia", "vn", "volyn", "yalta", "zaporizhzhe", "zaporizhzhia", "zhitomir", "zhytomyr", "zp", "zt", "ac", "blogspot", "co", "com", "go", "ne", "or", "org", "sc", "ac", "co", "gov", "ltd", "me", "net", "nhs", "org", "plc", "police", "sch", "blogspot", "service", "ak", "al", "ar", "as", "az", "ca", "co", "ct", "dc", "de", "dni", "fed", "fl", "ga", "gu", "hi", "ia", "id", "il", "in", "is-by", "isa", "kids", "ks", "ky", "la", "land-4-sale", "ma", "md", "me", "mi", "mn", "mo", "ms", "mt", "nc", "nd", "ne", "nh", "nj", "nm", "nsn", "nv", "ny", "oh", "ok", "or", "pa", "pr", "ri", "sc", "sd", "stuff-4-sale", "tn", "tx", "ut", "va", "vi", "vt", "wa", "wi", "wv", "wy", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "chtr", "paroch", "pvt", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "k12", "lib", "cc", "cc", "k12", "lib", "com", "edu", "gub", "mil", "net", "org", "blogspot", "co", "com", "net", "org", "com", "edu", "gov", "mil", "net", "org", "arts", "co", "com", "e12", "edu", "firm", "gob", "gov", "info", "int", "mil", "net", "org", "rec", "store", "tec", "web", "co", "com", "k12", "net", "org", "ac", "biz", "blogspot", "com", "edu", "gov", "health", "info", "int", "name", "net", "org", "pro", "com", "edu", "net", "org", "com", "dyndns", "edu", "gov", "mypets", "net", "org", "xn--80au", "xn--90azh", "xn--c1avg", "xn--d1at", "xn--o1ac", "xn--o1ach", "ac", "agrica", "alt", "co", "edu", "gov", "grondar", "law", "mil", "net", "ngo", "nis", "nom", "org", "school", "tm", "web", "blogspot", } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/trace/000077500000000000000000000000001264464372400215365ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/trace/events.go000066400000000000000000000302071264464372400233730ustar00rootroot00000000000000// Copyright 2015 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 trace import ( "bytes" "fmt" "html/template" "io" "log" "net/http" "runtime" "sort" "strconv" "strings" "sync" "sync/atomic" "text/tabwriter" "time" ) var eventsTmpl = template.Must(template.New("events").Funcs(template.FuncMap{ "elapsed": elapsed, "trimSpace": strings.TrimSpace, }).Parse(eventsHTML)) const maxEventsPerLog = 100 type bucket struct { MaxErrAge time.Duration String string } var buckets = []bucket{ {0, "total"}, {10 * time.Second, "errs<10s"}, {1 * time.Minute, "errs<1m"}, {10 * time.Minute, "errs<10m"}, {1 * time.Hour, "errs<1h"}, {10 * time.Hour, "errs<10h"}, {24000 * time.Hour, "errors"}, } // RenderEvents renders the HTML page typically served at /debug/events. // It does not do any auth checking; see AuthRequest for the default auth check // used by the handler registered on http.DefaultServeMux. // req may be nil. func RenderEvents(w http.ResponseWriter, req *http.Request, sensitive bool) { now := time.Now() data := &struct { Families []string // family names Buckets []bucket Counts [][]int // eventLog count per family/bucket // Set when a bucket has been selected. Family string Bucket int EventLogs eventLogs Expanded bool }{ Buckets: buckets, } data.Families = make([]string, 0, len(families)) famMu.RLock() for name := range families { data.Families = append(data.Families, name) } famMu.RUnlock() sort.Strings(data.Families) // Count the number of eventLogs in each family for each error age. data.Counts = make([][]int, len(data.Families)) for i, name := range data.Families { // TODO(sameer): move this loop under the family lock. f := getEventFamily(name) data.Counts[i] = make([]int, len(data.Buckets)) for j, b := range data.Buckets { data.Counts[i][j] = f.Count(now, b.MaxErrAge) } } if req != nil { var ok bool data.Family, data.Bucket, ok = parseEventsArgs(req) if !ok { // No-op } else { data.EventLogs = getEventFamily(data.Family).Copy(now, buckets[data.Bucket].MaxErrAge) } if data.EventLogs != nil { defer data.EventLogs.Free() sort.Sort(data.EventLogs) } if exp, err := strconv.ParseBool(req.FormValue("exp")); err == nil { data.Expanded = exp } } famMu.RLock() defer famMu.RUnlock() if err := eventsTmpl.Execute(w, data); err != nil { log.Printf("net/trace: Failed executing template: %v", err) } } func parseEventsArgs(req *http.Request) (fam string, b int, ok bool) { fam, bStr := req.FormValue("fam"), req.FormValue("b") if fam == "" || bStr == "" { return "", 0, false } b, err := strconv.Atoi(bStr) if err != nil || b < 0 || b >= len(buckets) { return "", 0, false } return fam, b, true } // An EventLog provides a log of events associated with a specific object. type EventLog interface { // Printf formats its arguments with fmt.Sprintf and adds the // result to the event log. Printf(format string, a ...interface{}) // Errorf is like Printf, but it marks this event as an error. Errorf(format string, a ...interface{}) // Finish declares that this event log is complete. // The event log should not be used after calling this method. Finish() } // NewEventLog returns a new EventLog with the specified family name // and title. func NewEventLog(family, title string) EventLog { el := newEventLog() el.ref() el.Family, el.Title = family, title el.Start = time.Now() el.events = make([]logEntry, 0, maxEventsPerLog) el.stack = make([]uintptr, 32) n := runtime.Callers(2, el.stack) el.stack = el.stack[:n] getEventFamily(family).add(el) return el } func (el *eventLog) Finish() { getEventFamily(el.Family).remove(el) el.unref() // matches ref in New } var ( famMu sync.RWMutex families = make(map[string]*eventFamily) // family name => family ) func getEventFamily(fam string) *eventFamily { famMu.Lock() defer famMu.Unlock() f := families[fam] if f == nil { f = &eventFamily{} families[fam] = f } return f } type eventFamily struct { mu sync.RWMutex eventLogs eventLogs } func (f *eventFamily) add(el *eventLog) { f.mu.Lock() f.eventLogs = append(f.eventLogs, el) f.mu.Unlock() } func (f *eventFamily) remove(el *eventLog) { f.mu.Lock() defer f.mu.Unlock() for i, el0 := range f.eventLogs { if el == el0 { copy(f.eventLogs[i:], f.eventLogs[i+1:]) f.eventLogs = f.eventLogs[:len(f.eventLogs)-1] return } } } func (f *eventFamily) Count(now time.Time, maxErrAge time.Duration) (n int) { f.mu.RLock() defer f.mu.RUnlock() for _, el := range f.eventLogs { if el.hasRecentError(now, maxErrAge) { n++ } } return } func (f *eventFamily) Copy(now time.Time, maxErrAge time.Duration) (els eventLogs) { f.mu.RLock() defer f.mu.RUnlock() els = make(eventLogs, 0, len(f.eventLogs)) for _, el := range f.eventLogs { if el.hasRecentError(now, maxErrAge) { el.ref() els = append(els, el) } } return } type eventLogs []*eventLog // Free calls unref on each element of the list. func (els eventLogs) Free() { for _, el := range els { el.unref() } } // eventLogs may be sorted in reverse chronological order. func (els eventLogs) Len() int { return len(els) } func (els eventLogs) Less(i, j int) bool { return els[i].Start.After(els[j].Start) } func (els eventLogs) Swap(i, j int) { els[i], els[j] = els[j], els[i] } // A logEntry is a timestamped log entry in an event log. type logEntry struct { When time.Time Elapsed time.Duration // since previous event in log NewDay bool // whether this event is on a different day to the previous event What string IsErr bool } // WhenString returns a string representation of the elapsed time of the event. // It will include the date if midnight was crossed. func (e logEntry) WhenString() string { if e.NewDay { return e.When.Format("2006/01/02 15:04:05.000000") } return e.When.Format("15:04:05.000000") } // An eventLog represents an active event log. type eventLog struct { // Family is the top-level grouping of event logs to which this belongs. Family string // Title is the title of this event log. Title string // Timing information. Start time.Time // Call stack where this event log was created. stack []uintptr // Append-only sequence of events. // // TODO(sameer): change this to a ring buffer to avoid the array copy // when we hit maxEventsPerLog. mu sync.RWMutex events []logEntry LastErrorTime time.Time discarded int refs int32 // how many buckets this is in } func (el *eventLog) reset() { // Clear all but the mutex. Mutexes may not be copied, even when unlocked. el.Family = "" el.Title = "" el.Start = time.Time{} el.stack = nil el.events = nil el.LastErrorTime = time.Time{} el.discarded = 0 el.refs = 0 } func (el *eventLog) hasRecentError(now time.Time, maxErrAge time.Duration) bool { if maxErrAge == 0 { return true } el.mu.RLock() defer el.mu.RUnlock() return now.Sub(el.LastErrorTime) < maxErrAge } // delta returns the elapsed time since the last event or the log start, // and whether it spans midnight. // L >= el.mu func (el *eventLog) delta(t time.Time) (time.Duration, bool) { if len(el.events) == 0 { return t.Sub(el.Start), false } prev := el.events[len(el.events)-1].When return t.Sub(prev), prev.Day() != t.Day() } func (el *eventLog) Printf(format string, a ...interface{}) { el.printf(false, format, a...) } func (el *eventLog) Errorf(format string, a ...interface{}) { el.printf(true, format, a...) } func (el *eventLog) printf(isErr bool, format string, a ...interface{}) { e := logEntry{When: time.Now(), IsErr: isErr, What: fmt.Sprintf(format, a...)} el.mu.Lock() e.Elapsed, e.NewDay = el.delta(e.When) if len(el.events) < maxEventsPerLog { el.events = append(el.events, e) } else { // Discard the oldest event. if el.discarded == 0 { // el.discarded starts at two to count for the event it // is replacing, plus the next one that we are about to // drop. el.discarded = 2 } else { el.discarded++ } // TODO(sameer): if this causes allocations on a critical path, // change eventLog.What to be a fmt.Stringer, as in trace.go. el.events[0].What = fmt.Sprintf("(%d events discarded)", el.discarded) // The timestamp of the discarded meta-event should be // the time of the last event it is representing. el.events[0].When = el.events[1].When copy(el.events[1:], el.events[2:]) el.events[maxEventsPerLog-1] = e } if e.IsErr { el.LastErrorTime = e.When } el.mu.Unlock() } func (el *eventLog) ref() { atomic.AddInt32(&el.refs, 1) } func (el *eventLog) unref() { if atomic.AddInt32(&el.refs, -1) == 0 { freeEventLog(el) } } func (el *eventLog) When() string { return el.Start.Format("2006/01/02 15:04:05.000000") } func (el *eventLog) ElapsedTime() string { elapsed := time.Since(el.Start) return fmt.Sprintf("%.6f", elapsed.Seconds()) } func (el *eventLog) Stack() string { buf := new(bytes.Buffer) tw := tabwriter.NewWriter(buf, 1, 8, 1, '\t', 0) printStackRecord(tw, el.stack) tw.Flush() return buf.String() } // printStackRecord prints the function + source line information // for a single stack trace. // Adapted from runtime/pprof/pprof.go. func printStackRecord(w io.Writer, stk []uintptr) { for _, pc := range stk { f := runtime.FuncForPC(pc) if f == nil { continue } file, line := f.FileLine(pc) name := f.Name() // Hide runtime.goexit and any runtime functions at the beginning. if strings.HasPrefix(name, "runtime.") { continue } fmt.Fprintf(w, "# %s\t%s:%d\n", name, file, line) } } func (el *eventLog) Events() []logEntry { el.mu.RLock() defer el.mu.RUnlock() return el.events } // freeEventLogs is a freelist of *eventLog var freeEventLogs = make(chan *eventLog, 1000) // newEventLog returns a event log ready to use. func newEventLog() *eventLog { select { case el := <-freeEventLogs: return el default: return new(eventLog) } } // freeEventLog adds el to freeEventLogs if there's room. // This is non-blocking. func freeEventLog(el *eventLog) { el.reset() select { case freeEventLogs <- el: default: } } const eventsHTML = ` events

    /debug/events

  • {{range $i, $fam := .Families}} {{range $j, $bucket := $.Buckets}} {{$n := index $.Counts $i $j}} {{end}} {{end}}
    {{$fam}} {{if $n}}{{end}} [{{$n}} {{$bucket.String}}] {{if $n}}{{end}}
    {{if $.EventLogs}}


    Family: {{$.Family}}

    {{if $.Expanded}}{{end}} [Summary]{{if $.Expanded}}{{end}} {{if not $.Expanded}}{{end}} [Expanded]{{if not $.Expanded}}{{end}} {{range $el := $.EventLogs}} {{if $.Expanded}} {{range $el.Events}} {{end}} {{end}} {{end}}
    WhenElapsed
    {{$el.When}} {{$el.ElapsedTime}} {{$el.Title}}
    {{$el.Stack|trimSpace}}
    {{.WhenString}} {{elapsed .Elapsed}} .{{if .IsErr}}E{{else}}.{{end}}. {{.What}}
    {{end}} ` golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/trace/histogram.go000066400000000000000000000220461264464372400240660ustar00rootroot00000000000000// Copyright 2015 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 trace // This file implements histogramming for RPC statistics collection. import ( "bytes" "fmt" "html/template" "log" "math" "golang.org/x/net/internal/timeseries" ) const ( bucketCount = 38 ) // histogram keeps counts of values in buckets that are spaced // out in powers of 2: 0-1, 2-3, 4-7... // histogram implements timeseries.Observable type histogram struct { sum int64 // running total of measurements sumOfSquares float64 // square of running total buckets []int64 // bucketed values for histogram value int // holds a single value as an optimization valueCount int64 // number of values recorded for single value } // AddMeasurement records a value measurement observation to the histogram. func (h *histogram) addMeasurement(value int64) { // TODO: assert invariant h.sum += value h.sumOfSquares += float64(value) * float64(value) bucketIndex := getBucket(value) if h.valueCount == 0 || (h.valueCount > 0 && h.value == bucketIndex) { h.value = bucketIndex h.valueCount++ } else { h.allocateBuckets() h.buckets[bucketIndex]++ } } func (h *histogram) allocateBuckets() { if h.buckets == nil { h.buckets = make([]int64, bucketCount) h.buckets[h.value] = h.valueCount h.value = 0 h.valueCount = -1 } } func log2(i int64) int { n := 0 for ; i >= 0x100; i >>= 8 { n += 8 } for ; i > 0; i >>= 1 { n += 1 } return n } func getBucket(i int64) (index int) { index = log2(i) - 1 if index < 0 { index = 0 } if index >= bucketCount { index = bucketCount - 1 } return } // Total returns the number of recorded observations. func (h *histogram) total() (total int64) { if h.valueCount >= 0 { total = h.valueCount } for _, val := range h.buckets { total += int64(val) } return } // Average returns the average value of recorded observations. func (h *histogram) average() float64 { t := h.total() if t == 0 { return 0 } return float64(h.sum) / float64(t) } // Variance returns the variance of recorded observations. func (h *histogram) variance() float64 { t := float64(h.total()) if t == 0 { return 0 } s := float64(h.sum) / t return h.sumOfSquares/t - s*s } // StandardDeviation returns the standard deviation of recorded observations. func (h *histogram) standardDeviation() float64 { return math.Sqrt(h.variance()) } // PercentileBoundary estimates the value that the given fraction of recorded // observations are less than. func (h *histogram) percentileBoundary(percentile float64) int64 { total := h.total() // Corner cases (make sure result is strictly less than Total()) if total == 0 { return 0 } else if total == 1 { return int64(h.average()) } percentOfTotal := round(float64(total) * percentile) var runningTotal int64 for i := range h.buckets { value := h.buckets[i] runningTotal += value if runningTotal == percentOfTotal { // We hit an exact bucket boundary. If the next bucket has data, it is a // good estimate of the value. If the bucket is empty, we interpolate the // midpoint between the next bucket's boundary and the next non-zero // bucket. If the remaining buckets are all empty, then we use the // boundary for the next bucket as the estimate. j := uint8(i + 1) min := bucketBoundary(j) if runningTotal < total { for h.buckets[j] == 0 { j++ } } max := bucketBoundary(j) return min + round(float64(max-min)/2) } else if runningTotal > percentOfTotal { // The value is in this bucket. Interpolate the value. delta := runningTotal - percentOfTotal percentBucket := float64(value-delta) / float64(value) bucketMin := bucketBoundary(uint8(i)) nextBucketMin := bucketBoundary(uint8(i + 1)) bucketSize := nextBucketMin - bucketMin return bucketMin + round(percentBucket*float64(bucketSize)) } } return bucketBoundary(bucketCount - 1) } // Median returns the estimated median of the observed values. func (h *histogram) median() int64 { return h.percentileBoundary(0.5) } // Add adds other to h. func (h *histogram) Add(other timeseries.Observable) { o := other.(*histogram) if o.valueCount == 0 { // Other histogram is empty } else if h.valueCount >= 0 && o.valueCount > 0 && h.value == o.value { // Both have a single bucketed value, aggregate them h.valueCount += o.valueCount } else { // Two different values necessitate buckets in this histogram h.allocateBuckets() if o.valueCount >= 0 { h.buckets[o.value] += o.valueCount } else { for i := range h.buckets { h.buckets[i] += o.buckets[i] } } } h.sumOfSquares += o.sumOfSquares h.sum += o.sum } // Clear resets the histogram to an empty state, removing all observed values. func (h *histogram) Clear() { h.buckets = nil h.value = 0 h.valueCount = 0 h.sum = 0 h.sumOfSquares = 0 } // CopyFrom copies from other, which must be a *histogram, into h. func (h *histogram) CopyFrom(other timeseries.Observable) { o := other.(*histogram) if o.valueCount == -1 { h.allocateBuckets() copy(h.buckets, o.buckets) } h.sum = o.sum h.sumOfSquares = o.sumOfSquares h.value = o.value h.valueCount = o.valueCount } // Multiply scales the histogram by the specified ratio. func (h *histogram) Multiply(ratio float64) { if h.valueCount == -1 { for i := range h.buckets { h.buckets[i] = int64(float64(h.buckets[i]) * ratio) } } else { h.valueCount = int64(float64(h.valueCount) * ratio) } h.sum = int64(float64(h.sum) * ratio) h.sumOfSquares = h.sumOfSquares * ratio } // New creates a new histogram. func (h *histogram) New() timeseries.Observable { r := new(histogram) r.Clear() return r } func (h *histogram) String() string { return fmt.Sprintf("%d, %f, %d, %d, %v", h.sum, h.sumOfSquares, h.value, h.valueCount, h.buckets) } // round returns the closest int64 to the argument func round(in float64) int64 { return int64(math.Floor(in + 0.5)) } // bucketBoundary returns the first value in the bucket. func bucketBoundary(bucket uint8) int64 { if bucket == 0 { return 0 } return 1 << bucket } // bucketData holds data about a specific bucket for use in distTmpl. type bucketData struct { Lower, Upper int64 N int64 Pct, CumulativePct float64 GraphWidth int } // data holds data about a Distribution for use in distTmpl. type data struct { Buckets []*bucketData Count, Median int64 Mean, StandardDeviation float64 } // maxHTMLBarWidth is the maximum width of the HTML bar for visualizing buckets. const maxHTMLBarWidth = 350.0 // newData returns data representing h for use in distTmpl. func (h *histogram) newData() *data { // Force the allocation of buckets to simplify the rendering implementation h.allocateBuckets() // We scale the bars on the right so that the largest bar is // maxHTMLBarWidth pixels in width. maxBucket := int64(0) for _, n := range h.buckets { if n > maxBucket { maxBucket = n } } total := h.total() barsizeMult := maxHTMLBarWidth / float64(maxBucket) var pctMult float64 if total == 0 { pctMult = 1.0 } else { pctMult = 100.0 / float64(total) } buckets := make([]*bucketData, len(h.buckets)) runningTotal := int64(0) for i, n := range h.buckets { if n == 0 { continue } runningTotal += n var upperBound int64 if i < bucketCount-1 { upperBound = bucketBoundary(uint8(i + 1)) } else { upperBound = math.MaxInt64 } buckets[i] = &bucketData{ Lower: bucketBoundary(uint8(i)), Upper: upperBound, N: n, Pct: float64(n) * pctMult, CumulativePct: float64(runningTotal) * pctMult, GraphWidth: int(float64(n) * barsizeMult), } } return &data{ Buckets: buckets, Count: total, Median: h.median(), Mean: h.average(), StandardDeviation: h.standardDeviation(), } } func (h *histogram) html() template.HTML { buf := new(bytes.Buffer) if err := distTmpl.Execute(buf, h.newData()); err != nil { buf.Reset() log.Printf("net/trace: couldn't execute template: %v", err) } return template.HTML(buf.String()) } // Input: data var distTmpl = template.Must(template.New("distTmpl").Parse(`
    Count: {{.Count}} Mean: {{printf "%.0f" .Mean}} StdDev: {{printf "%.0f" .StandardDeviation}} Median: {{.Median}}

    {{range $b := .Buckets}} {{if $b}} {{end}} {{end}}
    [ {{.Lower}}, {{.Upper}}) {{.N}} {{printf "%#.3f" .Pct}}% {{printf "%#.3f" .CumulativePct}}%
    `)) golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/trace/histogram_test.go000066400000000000000000000165571264464372400251370ustar00rootroot00000000000000// Copyright 2015 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 trace import ( "math" "testing" ) type sumTest struct { value int64 sum int64 sumOfSquares float64 total int64 } var sumTests = []sumTest{ {100, 100, 10000, 1}, {50, 150, 12500, 2}, {50, 200, 15000, 3}, {50, 250, 17500, 4}, } type bucketingTest struct { in int64 log int bucket int } var bucketingTests = []bucketingTest{ {0, 0, 0}, {1, 1, 0}, {2, 2, 1}, {3, 2, 1}, {4, 3, 2}, {1000, 10, 9}, {1023, 10, 9}, {1024, 11, 10}, {1000000, 20, 19}, } type multiplyTest struct { in int64 ratio float64 expectedSum int64 expectedTotal int64 expectedSumOfSquares float64 } var multiplyTests = []multiplyTest{ {15, 2.5, 37, 2, 562.5}, {128, 4.6, 758, 13, 77953.9}, } type percentileTest struct { fraction float64 expected int64 } var percentileTests = []percentileTest{ {0.25, 48}, {0.5, 96}, {0.6, 109}, {0.75, 128}, {0.90, 205}, {0.95, 230}, {0.99, 256}, } func TestSum(t *testing.T) { var h histogram for _, test := range sumTests { h.addMeasurement(test.value) sum := h.sum if sum != test.sum { t.Errorf("h.Sum = %v WANT: %v", sum, test.sum) } sumOfSquares := h.sumOfSquares if sumOfSquares != test.sumOfSquares { t.Errorf("h.SumOfSquares = %v WANT: %v", sumOfSquares, test.sumOfSquares) } total := h.total() if total != test.total { t.Errorf("h.Total = %v WANT: %v", total, test.total) } } } func TestMultiply(t *testing.T) { var h histogram for i, test := range multiplyTests { h.addMeasurement(test.in) h.Multiply(test.ratio) if h.sum != test.expectedSum { t.Errorf("#%v: h.sum = %v WANT: %v", i, h.sum, test.expectedSum) } if h.total() != test.expectedTotal { t.Errorf("#%v: h.total = %v WANT: %v", i, h.total(), test.expectedTotal) } if h.sumOfSquares != test.expectedSumOfSquares { t.Errorf("#%v: h.SumOfSquares = %v WANT: %v", i, test.expectedSumOfSquares, h.sumOfSquares) } } } func TestBucketingFunctions(t *testing.T) { for _, test := range bucketingTests { log := log2(test.in) if log != test.log { t.Errorf("log2 = %v WANT: %v", log, test.log) } bucket := getBucket(test.in) if bucket != test.bucket { t.Errorf("getBucket = %v WANT: %v", bucket, test.bucket) } } } func TestAverage(t *testing.T) { a := new(histogram) average := a.average() if average != 0 { t.Errorf("Average of empty histogram was %v WANT: 0", average) } a.addMeasurement(1) a.addMeasurement(1) a.addMeasurement(3) const expected = float64(5) / float64(3) average = a.average() if !isApproximate(average, expected) { t.Errorf("Average = %g WANT: %v", average, expected) } } func TestStandardDeviation(t *testing.T) { a := new(histogram) add(a, 10, 1<<4) add(a, 10, 1<<5) add(a, 10, 1<<6) stdDev := a.standardDeviation() const expected = 19.95 if !isApproximate(stdDev, expected) { t.Errorf("StandardDeviation = %v WANT: %v", stdDev, expected) } // No values a = new(histogram) stdDev = a.standardDeviation() if !isApproximate(stdDev, 0) { t.Errorf("StandardDeviation = %v WANT: 0", stdDev) } add(a, 1, 1<<4) if !isApproximate(stdDev, 0) { t.Errorf("StandardDeviation = %v WANT: 0", stdDev) } add(a, 10, 1<<4) if !isApproximate(stdDev, 0) { t.Errorf("StandardDeviation = %v WANT: 0", stdDev) } } func TestPercentileBoundary(t *testing.T) { a := new(histogram) add(a, 5, 1<<4) add(a, 10, 1<<6) add(a, 5, 1<<7) for _, test := range percentileTests { percentile := a.percentileBoundary(test.fraction) if percentile != test.expected { t.Errorf("h.PercentileBoundary (fraction=%v) = %v WANT: %v", test.fraction, percentile, test.expected) } } } func TestCopyFrom(t *testing.T) { a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1} b := histogram{6, 36, []int64{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}, 5, -1} a.CopyFrom(&b) if a.String() != b.String() { t.Errorf("a.String = %s WANT: %s", a.String(), b.String()) } } func TestClear(t *testing.T) { a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1} a.Clear() expected := "0, 0.000000, 0, 0, []" if a.String() != expected { t.Errorf("a.String = %s WANT %s", a.String(), expected) } } func TestNew(t *testing.T) { a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1} b := a.New() expected := "0, 0.000000, 0, 0, []" if b.(*histogram).String() != expected { t.Errorf("b.(*histogram).String = %s WANT: %s", b.(*histogram).String(), expected) } } func TestAdd(t *testing.T) { // The tests here depend on the associativity of addMeasurement and Add. // Add empty observation a := histogram{5, 25, []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, 4, -1} b := a.New() expected := a.String() a.Add(b) if a.String() != expected { t.Errorf("a.String = %s WANT: %s", a.String(), expected) } // Add same bucketed value, no new buckets c := new(histogram) d := new(histogram) e := new(histogram) c.addMeasurement(12) d.addMeasurement(11) e.addMeasurement(12) e.addMeasurement(11) c.Add(d) if c.String() != e.String() { t.Errorf("c.String = %s WANT: %s", c.String(), e.String()) } // Add bucketed values f := new(histogram) g := new(histogram) h := new(histogram) f.addMeasurement(4) f.addMeasurement(12) f.addMeasurement(100) g.addMeasurement(18) g.addMeasurement(36) g.addMeasurement(255) h.addMeasurement(4) h.addMeasurement(12) h.addMeasurement(100) h.addMeasurement(18) h.addMeasurement(36) h.addMeasurement(255) f.Add(g) if f.String() != h.String() { t.Errorf("f.String = %q WANT: %q", f.String(), h.String()) } // add buckets to no buckets i := new(histogram) j := new(histogram) k := new(histogram) j.addMeasurement(18) j.addMeasurement(36) j.addMeasurement(255) k.addMeasurement(18) k.addMeasurement(36) k.addMeasurement(255) i.Add(j) if i.String() != k.String() { t.Errorf("i.String = %q WANT: %q", i.String(), k.String()) } // add buckets to single value (no overlap) l := new(histogram) m := new(histogram) n := new(histogram) l.addMeasurement(0) m.addMeasurement(18) m.addMeasurement(36) m.addMeasurement(255) n.addMeasurement(0) n.addMeasurement(18) n.addMeasurement(36) n.addMeasurement(255) l.Add(m) if l.String() != n.String() { t.Errorf("l.String = %q WANT: %q", l.String(), n.String()) } // mixed order o := new(histogram) p := new(histogram) o.addMeasurement(0) o.addMeasurement(2) o.addMeasurement(0) p.addMeasurement(0) p.addMeasurement(0) p.addMeasurement(2) if o.String() != p.String() { t.Errorf("o.String = %q WANT: %q", o.String(), p.String()) } } func add(h *histogram, times int, val int64) { for i := 0; i < times; i++ { h.addMeasurement(val) } } func isApproximate(x, y float64) bool { return math.Abs(x-y) < 1e-2 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/trace/trace.go000066400000000000000000000646031264464372400231740ustar00rootroot00000000000000// Copyright 2015 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 trace implements tracing of requests and long-lived objects. It exports HTTP interfaces on /debug/requests and /debug/events. A trace.Trace provides tracing for short-lived objects, usually requests. A request handler might be implemented like this: func fooHandler(w http.ResponseWriter, req *http.Request) { tr := trace.New("mypkg.Foo", req.URL.Path) defer tr.Finish() ... tr.LazyPrintf("some event %q happened", str) ... if err := somethingImportant(); err != nil { tr.LazyPrintf("somethingImportant failed: %v", err) tr.SetError() } } The /debug/requests HTTP endpoint organizes the traces by family, errors, and duration. It also provides histogram of request duration for each family. A trace.EventLog provides tracing for long-lived objects, such as RPC connections. // A Fetcher fetches URL paths for a single domain. type Fetcher struct { domain string events trace.EventLog } func NewFetcher(domain string) *Fetcher { return &Fetcher{ domain, trace.NewEventLog("mypkg.Fetcher", domain), } } func (f *Fetcher) Fetch(path string) (string, error) { resp, err := http.Get("http://" + f.domain + "/" + path) if err != nil { f.events.Errorf("Get(%q) = %v", path, err) return "", err } f.events.Printf("Get(%q) = %s", path, resp.Status) ... } func (f *Fetcher) Close() error { f.events.Finish() return nil } The /debug/events HTTP endpoint organizes the event logs by family and by time since the last error. The expanded view displays recent log entries and the log's call stack. */ package trace // import "golang.org/x/net/trace" import ( "bytes" "fmt" "html/template" "io" "log" "net" "net/http" "runtime" "sort" "strconv" "sync" "sync/atomic" "time" "golang.org/x/net/context" "golang.org/x/net/internal/timeseries" ) // DebugUseAfterFinish controls whether to debug uses of Trace values after finishing. // FOR DEBUGGING ONLY. This will slow down the program. var DebugUseAfterFinish = false // AuthRequest determines whether a specific request is permitted to load the // /debug/requests or /debug/events pages. // // It returns two bools; the first indicates whether the page may be viewed at all, // and the second indicates whether sensitive events will be shown. // // AuthRequest may be replaced by a program to customise its authorisation requirements. // // The default AuthRequest function returns (true, true) iff the request comes from localhost/127.0.0.1/[::1]. var AuthRequest = func(req *http.Request) (any, sensitive bool) { host, _, err := net.SplitHostPort(req.RemoteAddr) switch { case err != nil: // Badly formed address; fail closed. return false, false case host == "localhost" || host == "127.0.0.1" || host == "::1": return true, true default: return false, false } } func init() { http.HandleFunc("/debug/requests", func(w http.ResponseWriter, req *http.Request) { any, sensitive := AuthRequest(req) if !any { http.Error(w, "not allowed", http.StatusUnauthorized) return } w.Header().Set("Content-Type", "text/html; charset=utf-8") Render(w, req, sensitive) }) http.HandleFunc("/debug/events", func(w http.ResponseWriter, req *http.Request) { any, sensitive := AuthRequest(req) if !any { http.Error(w, "not allowed", http.StatusUnauthorized) return } w.Header().Set("Content-Type", "text/html; charset=utf-8") RenderEvents(w, req, sensitive) }) } // Render renders the HTML page typically served at /debug/requests. // It does not do any auth checking; see AuthRequest for the default auth check // used by the handler registered on http.DefaultServeMux. // req may be nil. func Render(w io.Writer, req *http.Request, sensitive bool) { data := &struct { Families []string ActiveTraceCount map[string]int CompletedTraces map[string]*family // Set when a bucket has been selected. Traces traceList Family string Bucket int Expanded bool Traced bool Active bool ShowSensitive bool // whether to show sensitive events Histogram template.HTML HistogramWindow string // e.g. "last minute", "last hour", "all time" // If non-zero, the set of traces is a partial set, // and this is the total number. Total int }{ CompletedTraces: completedTraces, } data.ShowSensitive = sensitive if req != nil { // Allow show_sensitive=0 to force hiding of sensitive data for testing. // This only goes one way; you can't use show_sensitive=1 to see things. if req.FormValue("show_sensitive") == "0" { data.ShowSensitive = false } if exp, err := strconv.ParseBool(req.FormValue("exp")); err == nil { data.Expanded = exp } if exp, err := strconv.ParseBool(req.FormValue("rtraced")); err == nil { data.Traced = exp } } completedMu.RLock() data.Families = make([]string, 0, len(completedTraces)) for fam := range completedTraces { data.Families = append(data.Families, fam) } completedMu.RUnlock() sort.Strings(data.Families) // We are careful here to minimize the time spent locking activeMu, // since that lock is required every time an RPC starts and finishes. data.ActiveTraceCount = make(map[string]int, len(data.Families)) activeMu.RLock() for fam, s := range activeTraces { data.ActiveTraceCount[fam] = s.Len() } activeMu.RUnlock() var ok bool data.Family, data.Bucket, ok = parseArgs(req) switch { case !ok: // No-op case data.Bucket == -1: data.Active = true n := data.ActiveTraceCount[data.Family] data.Traces = getActiveTraces(data.Family) if len(data.Traces) < n { data.Total = n } case data.Bucket < bucketsPerFamily: if b := lookupBucket(data.Family, data.Bucket); b != nil { data.Traces = b.Copy(data.Traced) } default: if f := getFamily(data.Family, false); f != nil { var obs timeseries.Observable f.LatencyMu.RLock() switch o := data.Bucket - bucketsPerFamily; o { case 0: obs = f.Latency.Minute() data.HistogramWindow = "last minute" case 1: obs = f.Latency.Hour() data.HistogramWindow = "last hour" case 2: obs = f.Latency.Total() data.HistogramWindow = "all time" } f.LatencyMu.RUnlock() if obs != nil { data.Histogram = obs.(*histogram).html() } } } if data.Traces != nil { defer data.Traces.Free() sort.Sort(data.Traces) } completedMu.RLock() defer completedMu.RUnlock() if err := pageTmpl.ExecuteTemplate(w, "Page", data); err != nil { log.Printf("net/trace: Failed executing template: %v", err) } } func parseArgs(req *http.Request) (fam string, b int, ok bool) { if req == nil { return "", 0, false } fam, bStr := req.FormValue("fam"), req.FormValue("b") if fam == "" || bStr == "" { return "", 0, false } b, err := strconv.Atoi(bStr) if err != nil || b < -1 { return "", 0, false } return fam, b, true } func lookupBucket(fam string, b int) *traceBucket { f := getFamily(fam, false) if f == nil || b < 0 || b >= len(f.Buckets) { return nil } return f.Buckets[b] } type contextKeyT string var contextKey = contextKeyT("golang.org/x/net/trace.Trace") // NewContext returns a copy of the parent context // and associates it with a Trace. func NewContext(ctx context.Context, tr Trace) context.Context { return context.WithValue(ctx, contextKey, tr) } // FromContext returns the Trace bound to the context, if any. func FromContext(ctx context.Context) (tr Trace, ok bool) { tr, ok = ctx.Value(contextKey).(Trace) return } // Trace represents an active request. type Trace interface { // LazyLog adds x to the event log. It will be evaluated each time the // /debug/requests page is rendered. Any memory referenced by x will be // pinned until the trace is finished and later discarded. LazyLog(x fmt.Stringer, sensitive bool) // LazyPrintf evaluates its arguments with fmt.Sprintf each time the // /debug/requests page is rendered. Any memory referenced by a will be // pinned until the trace is finished and later discarded. LazyPrintf(format string, a ...interface{}) // SetError declares that this trace resulted in an error. SetError() // SetRecycler sets a recycler for the trace. // f will be called for each event passed to LazyLog at a time when // it is no longer required, whether while the trace is still active // and the event is discarded, or when a completed trace is discarded. SetRecycler(f func(interface{})) // SetTraceInfo sets the trace info for the trace. // This is currently unused. SetTraceInfo(traceID, spanID uint64) // SetMaxEvents sets the maximum number of events that will be stored // in the trace. This has no effect if any events have already been // added to the trace. SetMaxEvents(m int) // Finish declares that this trace is complete. // The trace should not be used after calling this method. Finish() } type lazySprintf struct { format string a []interface{} } func (l *lazySprintf) String() string { return fmt.Sprintf(l.format, l.a...) } // New returns a new Trace with the specified family and title. func New(family, title string) Trace { tr := newTrace() tr.ref() tr.Family, tr.Title = family, title tr.Start = time.Now() tr.events = make([]event, 0, maxEventsPerTrace) activeMu.RLock() s := activeTraces[tr.Family] activeMu.RUnlock() if s == nil { activeMu.Lock() s = activeTraces[tr.Family] // check again if s == nil { s = new(traceSet) activeTraces[tr.Family] = s } activeMu.Unlock() } s.Add(tr) // Trigger allocation of the completed trace structure for this family. // This will cause the family to be present in the request page during // the first trace of this family. We don't care about the return value, // nor is there any need for this to run inline, so we execute it in its // own goroutine, but only if the family isn't allocated yet. completedMu.RLock() if _, ok := completedTraces[tr.Family]; !ok { go allocFamily(tr.Family) } completedMu.RUnlock() return tr } func (tr *trace) Finish() { tr.Elapsed = time.Now().Sub(tr.Start) if DebugUseAfterFinish { buf := make([]byte, 4<<10) // 4 KB should be enough n := runtime.Stack(buf, false) tr.finishStack = buf[:n] } activeMu.RLock() m := activeTraces[tr.Family] activeMu.RUnlock() m.Remove(tr) f := getFamily(tr.Family, true) for _, b := range f.Buckets { if b.Cond.match(tr) { b.Add(tr) } } // Add a sample of elapsed time as microseconds to the family's timeseries h := new(histogram) h.addMeasurement(tr.Elapsed.Nanoseconds() / 1e3) f.LatencyMu.Lock() f.Latency.Add(h) f.LatencyMu.Unlock() tr.unref() // matches ref in New } const ( bucketsPerFamily = 9 tracesPerBucket = 10 maxActiveTraces = 20 // Maximum number of active traces to show. maxEventsPerTrace = 10 numHistogramBuckets = 38 ) var ( // The active traces. activeMu sync.RWMutex activeTraces = make(map[string]*traceSet) // family -> traces // Families of completed traces. completedMu sync.RWMutex completedTraces = make(map[string]*family) // family -> traces ) type traceSet struct { mu sync.RWMutex m map[*trace]bool // We could avoid the entire map scan in FirstN by having a slice of all the traces // ordered by start time, and an index into that from the trace struct, with a periodic // repack of the slice after enough traces finish; we could also use a skip list or similar. // However, that would shift some of the expense from /debug/requests time to RPC time, // which is probably the wrong trade-off. } func (ts *traceSet) Len() int { ts.mu.RLock() defer ts.mu.RUnlock() return len(ts.m) } func (ts *traceSet) Add(tr *trace) { ts.mu.Lock() if ts.m == nil { ts.m = make(map[*trace]bool) } ts.m[tr] = true ts.mu.Unlock() } func (ts *traceSet) Remove(tr *trace) { ts.mu.Lock() delete(ts.m, tr) ts.mu.Unlock() } // FirstN returns the first n traces ordered by time. func (ts *traceSet) FirstN(n int) traceList { ts.mu.RLock() defer ts.mu.RUnlock() if n > len(ts.m) { n = len(ts.m) } trl := make(traceList, 0, n) // Fast path for when no selectivity is needed. if n == len(ts.m) { for tr := range ts.m { tr.ref() trl = append(trl, tr) } sort.Sort(trl) return trl } // Pick the oldest n traces. // This is inefficient. See the comment in the traceSet struct. for tr := range ts.m { // Put the first n traces into trl in the order they occur. // When we have n, sort trl, and thereafter maintain its order. if len(trl) < n { tr.ref() trl = append(trl, tr) if len(trl) == n { // This is guaranteed to happen exactly once during this loop. sort.Sort(trl) } continue } if tr.Start.After(trl[n-1].Start) { continue } // Find where to insert this one. tr.ref() i := sort.Search(n, func(i int) bool { return trl[i].Start.After(tr.Start) }) trl[n-1].unref() copy(trl[i+1:], trl[i:]) trl[i] = tr } return trl } func getActiveTraces(fam string) traceList { activeMu.RLock() s := activeTraces[fam] activeMu.RUnlock() if s == nil { return nil } return s.FirstN(maxActiveTraces) } func getFamily(fam string, allocNew bool) *family { completedMu.RLock() f := completedTraces[fam] completedMu.RUnlock() if f == nil && allocNew { f = allocFamily(fam) } return f } func allocFamily(fam string) *family { completedMu.Lock() defer completedMu.Unlock() f := completedTraces[fam] if f == nil { f = newFamily() completedTraces[fam] = f } return f } // family represents a set of trace buckets and associated latency information. type family struct { // traces may occur in multiple buckets. Buckets [bucketsPerFamily]*traceBucket // latency time series LatencyMu sync.RWMutex Latency *timeseries.MinuteHourSeries } func newFamily() *family { return &family{ Buckets: [bucketsPerFamily]*traceBucket{ {Cond: minCond(0)}, {Cond: minCond(50 * time.Millisecond)}, {Cond: minCond(100 * time.Millisecond)}, {Cond: minCond(200 * time.Millisecond)}, {Cond: minCond(500 * time.Millisecond)}, {Cond: minCond(1 * time.Second)}, {Cond: minCond(10 * time.Second)}, {Cond: minCond(100 * time.Second)}, {Cond: errorCond{}}, }, Latency: timeseries.NewMinuteHourSeries(func() timeseries.Observable { return new(histogram) }), } } // traceBucket represents a size-capped bucket of historic traces, // along with a condition for a trace to belong to the bucket. type traceBucket struct { Cond cond // Ring buffer implementation of a fixed-size FIFO queue. mu sync.RWMutex buf [tracesPerBucket]*trace start int // < tracesPerBucket length int // <= tracesPerBucket } func (b *traceBucket) Add(tr *trace) { b.mu.Lock() defer b.mu.Unlock() i := b.start + b.length if i >= tracesPerBucket { i -= tracesPerBucket } if b.length == tracesPerBucket { // "Remove" an element from the bucket. b.buf[i].unref() b.start++ if b.start == tracesPerBucket { b.start = 0 } } b.buf[i] = tr if b.length < tracesPerBucket { b.length++ } tr.ref() } // Copy returns a copy of the traces in the bucket. // If tracedOnly is true, only the traces with trace information will be returned. // The logs will be ref'd before returning; the caller should call // the Free method when it is done with them. // TODO(dsymonds): keep track of traced requests in separate buckets. func (b *traceBucket) Copy(tracedOnly bool) traceList { b.mu.RLock() defer b.mu.RUnlock() trl := make(traceList, 0, b.length) for i, x := 0, b.start; i < b.length; i++ { tr := b.buf[x] if !tracedOnly || tr.spanID != 0 { tr.ref() trl = append(trl, tr) } x++ if x == b.length { x = 0 } } return trl } func (b *traceBucket) Empty() bool { b.mu.RLock() defer b.mu.RUnlock() return b.length == 0 } // cond represents a condition on a trace. type cond interface { match(t *trace) bool String() string } type minCond time.Duration func (m minCond) match(t *trace) bool { return t.Elapsed >= time.Duration(m) } func (m minCond) String() string { return fmt.Sprintf("≥%gs", time.Duration(m).Seconds()) } type errorCond struct{} func (e errorCond) match(t *trace) bool { return t.IsError } func (e errorCond) String() string { return "errors" } type traceList []*trace // Free calls unref on each element of the list. func (trl traceList) Free() { for _, t := range trl { t.unref() } } // traceList may be sorted in reverse chronological order. func (trl traceList) Len() int { return len(trl) } func (trl traceList) Less(i, j int) bool { return trl[i].Start.After(trl[j].Start) } func (trl traceList) Swap(i, j int) { trl[i], trl[j] = trl[j], trl[i] } // An event is a timestamped log entry in a trace. type event struct { When time.Time Elapsed time.Duration // since previous event in trace NewDay bool // whether this event is on a different day to the previous event Recyclable bool // whether this event was passed via LazyLog What interface{} // string or fmt.Stringer Sensitive bool // whether this event contains sensitive information } // WhenString returns a string representation of the elapsed time of the event. // It will include the date if midnight was crossed. func (e event) WhenString() string { if e.NewDay { return e.When.Format("2006/01/02 15:04:05.000000") } return e.When.Format("15:04:05.000000") } // discarded represents a number of discarded events. // It is stored as *discarded to make it easier to update in-place. type discarded int func (d *discarded) String() string { return fmt.Sprintf("(%d events discarded)", int(*d)) } // trace represents an active or complete request, // either sent or received by this program. type trace struct { // Family is the top-level grouping of traces to which this belongs. Family string // Title is the title of this trace. Title string // Timing information. Start time.Time Elapsed time.Duration // zero while active // Trace information if non-zero. traceID uint64 spanID uint64 // Whether this trace resulted in an error. IsError bool // Append-only sequence of events (modulo discards). mu sync.RWMutex events []event refs int32 // how many buckets this is in recycler func(interface{}) disc discarded // scratch space to avoid allocation finishStack []byte // where finish was called, if DebugUseAfterFinish is set } func (tr *trace) reset() { // Clear all but the mutex. Mutexes may not be copied, even when unlocked. tr.Family = "" tr.Title = "" tr.Start = time.Time{} tr.Elapsed = 0 tr.traceID = 0 tr.spanID = 0 tr.IsError = false tr.events = nil tr.refs = 0 tr.recycler = nil tr.disc = 0 tr.finishStack = nil } // delta returns the elapsed time since the last event or the trace start, // and whether it spans midnight. // L >= tr.mu func (tr *trace) delta(t time.Time) (time.Duration, bool) { if len(tr.events) == 0 { return t.Sub(tr.Start), false } prev := tr.events[len(tr.events)-1].When return t.Sub(prev), prev.Day() != t.Day() } func (tr *trace) addEvent(x interface{}, recyclable, sensitive bool) { if DebugUseAfterFinish && tr.finishStack != nil { buf := make([]byte, 4<<10) // 4 KB should be enough n := runtime.Stack(buf, false) log.Printf("net/trace: trace used after finish:\nFinished at:\n%s\nUsed at:\n%s", tr.finishStack, buf[:n]) } /* NOTE TO DEBUGGERS If you are here because your program panicked in this code, it is almost definitely the fault of code using this package, and very unlikely to be the fault of this code. The most likely scenario is that some code elsewhere is using a requestz.Trace after its Finish method is called. You can temporarily set the DebugUseAfterFinish var to help discover where that is; do not leave that var set, since it makes this package much less efficient. */ e := event{When: time.Now(), What: x, Recyclable: recyclable, Sensitive: sensitive} tr.mu.Lock() e.Elapsed, e.NewDay = tr.delta(e.When) if len(tr.events) < cap(tr.events) { tr.events = append(tr.events, e) } else { // Discard the middle events. di := int((cap(tr.events) - 1) / 2) if d, ok := tr.events[di].What.(*discarded); ok { (*d)++ } else { // disc starts at two to count for the event it is replacing, // plus the next one that we are about to drop. tr.disc = 2 if tr.recycler != nil && tr.events[di].Recyclable { go tr.recycler(tr.events[di].What) } tr.events[di].What = &tr.disc } // The timestamp of the discarded meta-event should be // the time of the last event it is representing. tr.events[di].When = tr.events[di+1].When if tr.recycler != nil && tr.events[di+1].Recyclable { go tr.recycler(tr.events[di+1].What) } copy(tr.events[di+1:], tr.events[di+2:]) tr.events[cap(tr.events)-1] = e } tr.mu.Unlock() } func (tr *trace) LazyLog(x fmt.Stringer, sensitive bool) { tr.addEvent(x, true, sensitive) } func (tr *trace) LazyPrintf(format string, a ...interface{}) { tr.addEvent(&lazySprintf{format, a}, false, false) } func (tr *trace) SetError() { tr.IsError = true } func (tr *trace) SetRecycler(f func(interface{})) { tr.recycler = f } func (tr *trace) SetTraceInfo(traceID, spanID uint64) { tr.traceID, tr.spanID = traceID, spanID } func (tr *trace) SetMaxEvents(m int) { // Always keep at least three events: first, discarded count, last. if len(tr.events) == 0 && m > 3 { tr.events = make([]event, 0, m) } } func (tr *trace) ref() { atomic.AddInt32(&tr.refs, 1) } func (tr *trace) unref() { if atomic.AddInt32(&tr.refs, -1) == 0 { if tr.recycler != nil { // freeTrace clears tr, so we hold tr.recycler and tr.events here. go func(f func(interface{}), es []event) { for _, e := range es { if e.Recyclable { f(e.What) } } }(tr.recycler, tr.events) } freeTrace(tr) } } func (tr *trace) When() string { return tr.Start.Format("2006/01/02 15:04:05.000000") } func (tr *trace) ElapsedTime() string { t := tr.Elapsed if t == 0 { // Active trace. t = time.Since(tr.Start) } return fmt.Sprintf("%.6f", t.Seconds()) } func (tr *trace) Events() []event { tr.mu.RLock() defer tr.mu.RUnlock() return tr.events } var traceFreeList = make(chan *trace, 1000) // TODO(dsymonds): Use sync.Pool? // newTrace returns a trace ready to use. func newTrace() *trace { select { case tr := <-traceFreeList: return tr default: return new(trace) } } // freeTrace adds tr to traceFreeList if there's room. // This is non-blocking. func freeTrace(tr *trace) { if DebugUseAfterFinish { return // never reuse } tr.reset() select { case traceFreeList <- tr: default: } } func elapsed(d time.Duration) string { b := []byte(fmt.Sprintf("%.6f", d.Seconds())) // For subsecond durations, blank all zeros before decimal point, // and all zeros between the decimal point and the first non-zero digit. if d < time.Second { dot := bytes.IndexByte(b, '.') for i := 0; i < dot; i++ { b[i] = ' ' } for i := dot + 1; i < len(b); i++ { if b[i] == '0' { b[i] = ' ' } else { break } } } return string(b) } var pageTmpl = template.Must(template.New("Page").Funcs(template.FuncMap{ "elapsed": elapsed, "add": func(a, b int) int { return a + b }, }).Parse(pageHTML)) const pageHTML = ` {{template "Prolog" .}} {{template "StatusTable" .}} {{template "Epilog" .}} {{define "Prolog"}} /debug/requests

    /debug/requests

    {{end}} {{/* end of Prolog */}} {{define "StatusTable"}} {{range $fam := .Families}} {{$n := index $.ActiveTraceCount $fam}} {{$f := index $.CompletedTraces $fam}} {{range $i, $b := $f.Buckets}} {{$empty := $b.Empty}} {{end}} {{$nb := len $f.Buckets}} {{end}}
    {{$fam}} {{if $n}}{{end}} [{{$n}} active] {{if $n}}{{end}} {{if not $empty}}{{end}} [{{.Cond}}] {{if not $empty}}{{end}} [minute] [hour] [total]
    {{end}} {{/* end of StatusTable */}} {{define "Epilog"}} {{if $.Traces}}

    Family: {{$.Family}}

    {{if or $.Expanded $.Traced}} [Normal/Summary] {{else}} [Normal/Summary] {{end}} {{if or (not $.Expanded) $.Traced}} [Normal/Expanded] {{else}} [Normal/Expanded] {{end}} {{if not $.Active}} {{if or $.Expanded (not $.Traced)}} [Traced/Summary] {{else}} [Traced/Summary] {{end}} {{if or (not $.Expanded) (not $.Traced)}} [Traced/Expanded] {{else}} [Traced/Expanded] {{end}} {{end}} {{if $.Total}}

    Showing {{len $.Traces}} of {{$.Total}} traces.

    {{end}} {{range $tr := $.Traces}} {{/* TODO: include traceID/spanID */}} {{if $.Expanded}} {{range $tr.Events}} {{end}} {{end}} {{end}}
    {{if $.Active}}Active{{else}}Completed{{end}} Requests
    WhenElapsed (s)
    {{$tr.When}} {{$tr.ElapsedTime}} {{$tr.Title}}
    {{.WhenString}} {{elapsed .Elapsed}} {{if or $.ShowSensitive (not .Sensitive)}}... {{.What}}{{else}}[redacted]{{end}}
    {{end}} {{/* if $.Traces */}} {{if $.Histogram}}

    Latency (µs) of {{$.Family}} over {{$.HistogramWindow}}

    {{$.Histogram}} {{end}} {{/* if $.Histogram */}} {{end}} {{/* end of Epilog */}} ` golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/trace/trace_test.go000066400000000000000000000017541264464372400242310ustar00rootroot00000000000000// Copyright 2015 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 trace import ( "reflect" "testing" ) type s struct{} func (s) String() string { return "lazy string" } // TestReset checks whether all the fields are zeroed after reset. func TestReset(t *testing.T) { tr := New("foo", "bar") tr.LazyLog(s{}, false) tr.LazyPrintf("%d", 1) tr.SetRecycler(func(_ interface{}) {}) tr.SetTraceInfo(3, 4) tr.SetMaxEvents(100) tr.SetError() tr.Finish() tr.(*trace).reset() if !reflect.DeepEqual(tr, new(trace)) { t.Errorf("reset didn't clear all fields: %+v", tr) } } // TestResetLog checks whether all the fields are zeroed after reset. func TestResetLog(t *testing.T) { el := NewEventLog("foo", "bar") el.Printf("message") el.Errorf("error") el.Finish() el.(*eventLog).reset() if !reflect.DeepEqual(el, new(eventLog)) { t.Errorf("reset didn't clear all fields: %+v", el) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/000077500000000000000000000000001264464372400217105ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/file.go000066400000000000000000000464671264464372400231770ustar00rootroot00000000000000// Copyright 2014 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 webdav import ( "io" "net/http" "os" "path" "path/filepath" "strings" "sync" "time" "golang.org/x/net/webdav/internal/xml" ) // slashClean is equivalent to but slightly more efficient than // path.Clean("/" + name). func slashClean(name string) string { if name == "" || name[0] != '/' { name = "/" + name } return path.Clean(name) } // A FileSystem implements access to a collection of named files. The elements // in a file path are separated by slash ('/', U+002F) characters, regardless // of host operating system convention. // // Each method has the same semantics as the os package's function of the same // name. // // Note that the os.Rename documentation says that "OS-specific restrictions // might apply". In particular, whether or not renaming a file or directory // overwriting another existing file or directory is an error is OS-dependent. type FileSystem interface { Mkdir(name string, perm os.FileMode) error OpenFile(name string, flag int, perm os.FileMode) (File, error) RemoveAll(name string) error Rename(oldName, newName string) error Stat(name string) (os.FileInfo, error) } // A File is returned by a FileSystem's OpenFile method and can be served by a // Handler. // // A File may optionally implement the DeadPropsHolder interface, if it can // load and save dead properties. type File interface { http.File io.Writer } // A Dir implements FileSystem using the native file system restricted to a // specific directory tree. // // While the FileSystem.OpenFile method takes '/'-separated paths, a Dir's // string value is a filename on the native file system, not a URL, so it is // separated by filepath.Separator, which isn't necessarily '/'. // // An empty Dir is treated as ".". type Dir string func (d Dir) resolve(name string) string { // This implementation is based on Dir.Open's code in the standard net/http package. if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || strings.Contains(name, "\x00") { return "" } dir := string(d) if dir == "" { dir = "." } return filepath.Join(dir, filepath.FromSlash(slashClean(name))) } func (d Dir) Mkdir(name string, perm os.FileMode) error { if name = d.resolve(name); name == "" { return os.ErrNotExist } return os.Mkdir(name, perm) } func (d Dir) OpenFile(name string, flag int, perm os.FileMode) (File, error) { if name = d.resolve(name); name == "" { return nil, os.ErrNotExist } f, err := os.OpenFile(name, flag, perm) if err != nil { return nil, err } return f, nil } func (d Dir) RemoveAll(name string) error { if name = d.resolve(name); name == "" { return os.ErrNotExist } if name == filepath.Clean(string(d)) { // Prohibit removing the virtual root directory. return os.ErrInvalid } return os.RemoveAll(name) } func (d Dir) Rename(oldName, newName string) error { if oldName = d.resolve(oldName); oldName == "" { return os.ErrNotExist } if newName = d.resolve(newName); newName == "" { return os.ErrNotExist } if root := filepath.Clean(string(d)); root == oldName || root == newName { // Prohibit renaming from or to the virtual root directory. return os.ErrInvalid } return os.Rename(oldName, newName) } func (d Dir) Stat(name string) (os.FileInfo, error) { if name = d.resolve(name); name == "" { return nil, os.ErrNotExist } return os.Stat(name) } // NewMemFS returns a new in-memory FileSystem implementation. func NewMemFS() FileSystem { return &memFS{ root: memFSNode{ children: make(map[string]*memFSNode), mode: 0660 | os.ModeDir, modTime: time.Now(), }, } } // A memFS implements FileSystem, storing all metadata and actual file data // in-memory. No limits on filesystem size are used, so it is not recommended // this be used where the clients are untrusted. // // Concurrent access is permitted. The tree structure is protected by a mutex, // and each node's contents and metadata are protected by a per-node mutex. // // TODO: Enforce file permissions. type memFS struct { mu sync.Mutex root memFSNode } // TODO: clean up and rationalize the walk/find code. // walk walks the directory tree for the fullname, calling f at each step. If f // returns an error, the walk will be aborted and return that same error. // // dir is the directory at that step, frag is the name fragment, and final is // whether it is the final step. For example, walking "/foo/bar/x" will result // in 3 calls to f: // - "/", "foo", false // - "/foo/", "bar", false // - "/foo/bar/", "x", true // The frag argument will be empty only if dir is the root node and the walk // ends at that root node. func (fs *memFS) walk(op, fullname string, f func(dir *memFSNode, frag string, final bool) error) error { original := fullname fullname = slashClean(fullname) // Strip any leading "/"s to make fullname a relative path, as the walk // starts at fs.root. if fullname[0] == '/' { fullname = fullname[1:] } dir := &fs.root for { frag, remaining := fullname, "" i := strings.IndexRune(fullname, '/') final := i < 0 if !final { frag, remaining = fullname[:i], fullname[i+1:] } if frag == "" && dir != &fs.root { panic("webdav: empty path fragment for a clean path") } if err := f(dir, frag, final); err != nil { return &os.PathError{ Op: op, Path: original, Err: err, } } if final { break } child := dir.children[frag] if child == nil { return &os.PathError{ Op: op, Path: original, Err: os.ErrNotExist, } } if !child.mode.IsDir() { return &os.PathError{ Op: op, Path: original, Err: os.ErrInvalid, } } dir, fullname = child, remaining } return nil } // find returns the parent of the named node and the relative name fragment // from the parent to the child. For example, if finding "/foo/bar/baz" then // parent will be the node for "/foo/bar" and frag will be "baz". // // If the fullname names the root node, then parent, frag and err will be zero. // // find returns an error if the parent does not already exist or the parent // isn't a directory, but it will not return an error per se if the child does // not already exist. The error returned is either nil or an *os.PathError // whose Op is op. func (fs *memFS) find(op, fullname string) (parent *memFSNode, frag string, err error) { err = fs.walk(op, fullname, func(parent0 *memFSNode, frag0 string, final bool) error { if !final { return nil } if frag0 != "" { parent, frag = parent0, frag0 } return nil }) return parent, frag, err } func (fs *memFS) Mkdir(name string, perm os.FileMode) error { fs.mu.Lock() defer fs.mu.Unlock() dir, frag, err := fs.find("mkdir", name) if err != nil { return err } if dir == nil { // We can't create the root. return os.ErrInvalid } if _, ok := dir.children[frag]; ok { return os.ErrExist } dir.children[frag] = &memFSNode{ children: make(map[string]*memFSNode), mode: perm.Perm() | os.ModeDir, modTime: time.Now(), } return nil } func (fs *memFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) { fs.mu.Lock() defer fs.mu.Unlock() dir, frag, err := fs.find("open", name) if err != nil { return nil, err } var n *memFSNode if dir == nil { // We're opening the root. if flag&(os.O_WRONLY|os.O_RDWR) != 0 { return nil, os.ErrPermission } n, frag = &fs.root, "/" } else { n = dir.children[frag] if flag&(os.O_SYNC|os.O_APPEND) != 0 { // memFile doesn't support these flags yet. return nil, os.ErrInvalid } if flag&os.O_CREATE != 0 { if flag&os.O_EXCL != 0 && n != nil { return nil, os.ErrExist } if n == nil { n = &memFSNode{ mode: perm.Perm(), } dir.children[frag] = n } } if n == nil { return nil, os.ErrNotExist } if flag&(os.O_WRONLY|os.O_RDWR) != 0 && flag&os.O_TRUNC != 0 { n.mu.Lock() n.data = nil n.mu.Unlock() } } children := make([]os.FileInfo, 0, len(n.children)) for cName, c := range n.children { children = append(children, c.stat(cName)) } return &memFile{ n: n, nameSnapshot: frag, childrenSnapshot: children, }, nil } func (fs *memFS) RemoveAll(name string) error { fs.mu.Lock() defer fs.mu.Unlock() dir, frag, err := fs.find("remove", name) if err != nil { return err } if dir == nil { // We can't remove the root. return os.ErrInvalid } delete(dir.children, frag) return nil } func (fs *memFS) Rename(oldName, newName string) error { fs.mu.Lock() defer fs.mu.Unlock() oldName = slashClean(oldName) newName = slashClean(newName) if oldName == newName { return nil } if strings.HasPrefix(newName, oldName+"/") { // We can't rename oldName to be a sub-directory of itself. return os.ErrInvalid } oDir, oFrag, err := fs.find("rename", oldName) if err != nil { return err } if oDir == nil { // We can't rename from the root. return os.ErrInvalid } nDir, nFrag, err := fs.find("rename", newName) if err != nil { return err } if nDir == nil { // We can't rename to the root. return os.ErrInvalid } oNode, ok := oDir.children[oFrag] if !ok { return os.ErrNotExist } if oNode.children != nil { if nNode, ok := nDir.children[nFrag]; ok { if nNode.children == nil { return errNotADirectory } if len(nNode.children) != 0 { return errDirectoryNotEmpty } } } delete(oDir.children, oFrag) nDir.children[nFrag] = oNode return nil } func (fs *memFS) Stat(name string) (os.FileInfo, error) { fs.mu.Lock() defer fs.mu.Unlock() dir, frag, err := fs.find("stat", name) if err != nil { return nil, err } if dir == nil { // We're stat'ting the root. return fs.root.stat("/"), nil } if n, ok := dir.children[frag]; ok { return n.stat(path.Base(name)), nil } return nil, os.ErrNotExist } // A memFSNode represents a single entry in the in-memory filesystem and also // implements os.FileInfo. type memFSNode struct { // children is protected by memFS.mu. children map[string]*memFSNode mu sync.Mutex data []byte mode os.FileMode modTime time.Time deadProps map[xml.Name]Property } func (n *memFSNode) stat(name string) *memFileInfo { n.mu.Lock() defer n.mu.Unlock() return &memFileInfo{ name: name, size: int64(len(n.data)), mode: n.mode, modTime: n.modTime, } } func (n *memFSNode) DeadProps() (map[xml.Name]Property, error) { n.mu.Lock() defer n.mu.Unlock() if len(n.deadProps) == 0 { return nil, nil } ret := make(map[xml.Name]Property, len(n.deadProps)) for k, v := range n.deadProps { ret[k] = v } return ret, nil } func (n *memFSNode) Patch(patches []Proppatch) ([]Propstat, error) { n.mu.Lock() defer n.mu.Unlock() pstat := Propstat{Status: http.StatusOK} for _, patch := range patches { for _, p := range patch.Props { pstat.Props = append(pstat.Props, Property{XMLName: p.XMLName}) if patch.Remove { delete(n.deadProps, p.XMLName) continue } if n.deadProps == nil { n.deadProps = map[xml.Name]Property{} } n.deadProps[p.XMLName] = p } } return []Propstat{pstat}, nil } type memFileInfo struct { name string size int64 mode os.FileMode modTime time.Time } func (f *memFileInfo) Name() string { return f.name } func (f *memFileInfo) Size() int64 { return f.size } func (f *memFileInfo) Mode() os.FileMode { return f.mode } func (f *memFileInfo) ModTime() time.Time { return f.modTime } func (f *memFileInfo) IsDir() bool { return f.mode.IsDir() } func (f *memFileInfo) Sys() interface{} { return nil } // A memFile is a File implementation for a memFSNode. It is a per-file (not // per-node) read/write position, and a snapshot of the memFS' tree structure // (a node's name and children) for that node. type memFile struct { n *memFSNode nameSnapshot string childrenSnapshot []os.FileInfo // pos is protected by n.mu. pos int } // A *memFile implements the optional DeadPropsHolder interface. var _ DeadPropsHolder = (*memFile)(nil) func (f *memFile) DeadProps() (map[xml.Name]Property, error) { return f.n.DeadProps() } func (f *memFile) Patch(patches []Proppatch) ([]Propstat, error) { return f.n.Patch(patches) } func (f *memFile) Close() error { return nil } func (f *memFile) Read(p []byte) (int, error) { f.n.mu.Lock() defer f.n.mu.Unlock() if f.n.mode.IsDir() { return 0, os.ErrInvalid } if f.pos >= len(f.n.data) { return 0, io.EOF } n := copy(p, f.n.data[f.pos:]) f.pos += n return n, nil } func (f *memFile) Readdir(count int) ([]os.FileInfo, error) { f.n.mu.Lock() defer f.n.mu.Unlock() if !f.n.mode.IsDir() { return nil, os.ErrInvalid } old := f.pos if old >= len(f.childrenSnapshot) { // The os.File Readdir docs say that at the end of a directory, // the error is io.EOF if count > 0 and nil if count <= 0. if count > 0 { return nil, io.EOF } return nil, nil } if count > 0 { f.pos += count if f.pos > len(f.childrenSnapshot) { f.pos = len(f.childrenSnapshot) } } else { f.pos = len(f.childrenSnapshot) old = 0 } return f.childrenSnapshot[old:f.pos], nil } func (f *memFile) Seek(offset int64, whence int) (int64, error) { f.n.mu.Lock() defer f.n.mu.Unlock() npos := f.pos // TODO: How to handle offsets greater than the size of system int? switch whence { case os.SEEK_SET: npos = int(offset) case os.SEEK_CUR: npos += int(offset) case os.SEEK_END: npos = len(f.n.data) + int(offset) default: npos = -1 } if npos < 0 { return 0, os.ErrInvalid } f.pos = npos return int64(f.pos), nil } func (f *memFile) Stat() (os.FileInfo, error) { return f.n.stat(f.nameSnapshot), nil } func (f *memFile) Write(p []byte) (int, error) { lenp := len(p) f.n.mu.Lock() defer f.n.mu.Unlock() if f.n.mode.IsDir() { return 0, os.ErrInvalid } if f.pos < len(f.n.data) { n := copy(f.n.data[f.pos:], p) f.pos += n p = p[n:] } else if f.pos > len(f.n.data) { // Write permits the creation of holes, if we've seek'ed past the // existing end of file. if f.pos <= cap(f.n.data) { oldLen := len(f.n.data) f.n.data = f.n.data[:f.pos] hole := f.n.data[oldLen:] for i := range hole { hole[i] = 0 } } else { d := make([]byte, f.pos, f.pos+len(p)) copy(d, f.n.data) f.n.data = d } } if len(p) > 0 { // We should only get here if f.pos == len(f.n.data). f.n.data = append(f.n.data, p...) f.pos = len(f.n.data) } f.n.modTime = time.Now() return lenp, nil } // moveFiles moves files and/or directories from src to dst. // // See section 9.9.4 for when various HTTP status codes apply. func moveFiles(fs FileSystem, src, dst string, overwrite bool) (status int, err error) { created := false if _, err := fs.Stat(dst); err != nil { if !os.IsNotExist(err) { return http.StatusForbidden, err } created = true } else if overwrite { // Section 9.9.3 says that "If a resource exists at the destination // and the Overwrite header is "T", then prior to performing the move, // the server must perform a DELETE with "Depth: infinity" on the // destination resource. if err := fs.RemoveAll(dst); err != nil { return http.StatusForbidden, err } } else { return http.StatusPreconditionFailed, os.ErrExist } if err := fs.Rename(src, dst); err != nil { return http.StatusForbidden, err } if created { return http.StatusCreated, nil } return http.StatusNoContent, nil } func copyProps(dst, src File) error { d, ok := dst.(DeadPropsHolder) if !ok { return nil } s, ok := src.(DeadPropsHolder) if !ok { return nil } m, err := s.DeadProps() if err != nil { return err } props := make([]Property, 0, len(m)) for _, prop := range m { props = append(props, prop) } _, err = d.Patch([]Proppatch{{Props: props}}) return err } // copyFiles copies files and/or directories from src to dst. // // See section 9.8.5 for when various HTTP status codes apply. func copyFiles(fs FileSystem, src, dst string, overwrite bool, depth int, recursion int) (status int, err error) { if recursion == 1000 { return http.StatusInternalServerError, errRecursionTooDeep } recursion++ // TODO: section 9.8.3 says that "Note that an infinite-depth COPY of /A/ // into /A/B/ could lead to infinite recursion if not handled correctly." srcFile, err := fs.OpenFile(src, os.O_RDONLY, 0) if err != nil { if os.IsNotExist(err) { return http.StatusNotFound, err } return http.StatusInternalServerError, err } defer srcFile.Close() srcStat, err := srcFile.Stat() if err != nil { if os.IsNotExist(err) { return http.StatusNotFound, err } return http.StatusInternalServerError, err } srcPerm := srcStat.Mode() & os.ModePerm created := false if _, err := fs.Stat(dst); err != nil { if os.IsNotExist(err) { created = true } else { return http.StatusForbidden, err } } else { if !overwrite { return http.StatusPreconditionFailed, os.ErrExist } if err := fs.RemoveAll(dst); err != nil && !os.IsNotExist(err) { return http.StatusForbidden, err } } if srcStat.IsDir() { if err := fs.Mkdir(dst, srcPerm); err != nil { return http.StatusForbidden, err } if depth == infiniteDepth { children, err := srcFile.Readdir(-1) if err != nil { return http.StatusForbidden, err } for _, c := range children { name := c.Name() s := path.Join(src, name) d := path.Join(dst, name) cStatus, cErr := copyFiles(fs, s, d, overwrite, depth, recursion) if cErr != nil { // TODO: MultiStatus. return cStatus, cErr } } } } else { dstFile, err := fs.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcPerm) if err != nil { if os.IsNotExist(err) { return http.StatusConflict, err } return http.StatusForbidden, err } _, copyErr := io.Copy(dstFile, srcFile) propsErr := copyProps(dstFile, srcFile) closeErr := dstFile.Close() if copyErr != nil { return http.StatusInternalServerError, copyErr } if propsErr != nil { return http.StatusInternalServerError, propsErr } if closeErr != nil { return http.StatusInternalServerError, closeErr } } if created { return http.StatusCreated, nil } return http.StatusNoContent, nil } // walkFS traverses filesystem fs starting at name up to depth levels. // // Allowed values for depth are 0, 1 or infiniteDepth. For each visited node, // walkFS calls walkFn. If a visited file system node is a directory and // walkFn returns filepath.SkipDir, walkFS will skip traversal of this node. func walkFS(fs FileSystem, depth int, name string, info os.FileInfo, walkFn filepath.WalkFunc) error { // This implementation is based on Walk's code in the standard path/filepath package. err := walkFn(name, info, nil) if err != nil { if info.IsDir() && err == filepath.SkipDir { return nil } return err } if !info.IsDir() || depth == 0 { return nil } if depth == 1 { depth = 0 } // Read directory names. f, err := fs.OpenFile(name, os.O_RDONLY, 0) if err != nil { return walkFn(name, info, err) } fileInfos, err := f.Readdir(0) f.Close() if err != nil { return walkFn(name, info, err) } for _, fileInfo := range fileInfos { filename := path.Join(name, fileInfo.Name()) fileInfo, err := fs.Stat(filename) if err != nil { if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { return err } } else { err = walkFS(fs, depth, filename, fileInfo, walkFn) if err != nil { if !fileInfo.IsDir() || err != filepath.SkipDir { return err } } } } return nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/file_test.go000066400000000000000000000655011264464372400242240ustar00rootroot00000000000000// Copyright 2014 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 webdav import ( "fmt" "io" "io/ioutil" "os" "path" "path/filepath" "reflect" "runtime" "sort" "strconv" "strings" "testing" "golang.org/x/net/webdav/internal/xml" ) func TestSlashClean(t *testing.T) { testCases := []string{ "", ".", "/", "/./", "//", "//.", "//a", "/a", "/a/b/c", "/a//b/./../c/d/", "a", "a/b/c", } for _, tc := range testCases { got := slashClean(tc) want := path.Clean("/" + tc) if got != want { t.Errorf("tc=%q: got %q, want %q", tc, got, want) } } } func TestDirResolve(t *testing.T) { testCases := []struct { dir, name, want string }{ {"/", "", "/"}, {"/", "/", "/"}, {"/", ".", "/"}, {"/", "./a", "/a"}, {"/", "..", "/"}, {"/", "..", "/"}, {"/", "../", "/"}, {"/", "../.", "/"}, {"/", "../a", "/a"}, {"/", "../..", "/"}, {"/", "../bar/a", "/bar/a"}, {"/", "../baz/a", "/baz/a"}, {"/", "...", "/..."}, {"/", ".../a", "/.../a"}, {"/", ".../..", "/"}, {"/", "a", "/a"}, {"/", "a/./b", "/a/b"}, {"/", "a/../../b", "/b"}, {"/", "a/../b", "/b"}, {"/", "a/b", "/a/b"}, {"/", "a/b/c/../../d", "/a/d"}, {"/", "a/b/c/../../../d", "/d"}, {"/", "a/b/c/../../../../d", "/d"}, {"/", "a/b/c/d", "/a/b/c/d"}, {"/foo/bar", "", "/foo/bar"}, {"/foo/bar", "/", "/foo/bar"}, {"/foo/bar", ".", "/foo/bar"}, {"/foo/bar", "./a", "/foo/bar/a"}, {"/foo/bar", "..", "/foo/bar"}, {"/foo/bar", "../", "/foo/bar"}, {"/foo/bar", "../.", "/foo/bar"}, {"/foo/bar", "../a", "/foo/bar/a"}, {"/foo/bar", "../..", "/foo/bar"}, {"/foo/bar", "../bar/a", "/foo/bar/bar/a"}, {"/foo/bar", "../baz/a", "/foo/bar/baz/a"}, {"/foo/bar", "...", "/foo/bar/..."}, {"/foo/bar", ".../a", "/foo/bar/.../a"}, {"/foo/bar", ".../..", "/foo/bar"}, {"/foo/bar", "a", "/foo/bar/a"}, {"/foo/bar", "a/./b", "/foo/bar/a/b"}, {"/foo/bar", "a/../../b", "/foo/bar/b"}, {"/foo/bar", "a/../b", "/foo/bar/b"}, {"/foo/bar", "a/b", "/foo/bar/a/b"}, {"/foo/bar", "a/b/c/../../d", "/foo/bar/a/d"}, {"/foo/bar", "a/b/c/../../../d", "/foo/bar/d"}, {"/foo/bar", "a/b/c/../../../../d", "/foo/bar/d"}, {"/foo/bar", "a/b/c/d", "/foo/bar/a/b/c/d"}, {"/foo/bar/", "", "/foo/bar"}, {"/foo/bar/", "/", "/foo/bar"}, {"/foo/bar/", ".", "/foo/bar"}, {"/foo/bar/", "./a", "/foo/bar/a"}, {"/foo/bar/", "..", "/foo/bar"}, {"/foo//bar///", "", "/foo/bar"}, {"/foo//bar///", "/", "/foo/bar"}, {"/foo//bar///", ".", "/foo/bar"}, {"/foo//bar///", "./a", "/foo/bar/a"}, {"/foo//bar///", "..", "/foo/bar"}, {"/x/y/z", "ab/c\x00d/ef", ""}, {".", "", "."}, {".", "/", "."}, {".", ".", "."}, {".", "./a", "a"}, {".", "..", "."}, {".", "..", "."}, {".", "../", "."}, {".", "../.", "."}, {".", "../a", "a"}, {".", "../..", "."}, {".", "../bar/a", "bar/a"}, {".", "../baz/a", "baz/a"}, {".", "...", "..."}, {".", ".../a", ".../a"}, {".", ".../..", "."}, {".", "a", "a"}, {".", "a/./b", "a/b"}, {".", "a/../../b", "b"}, {".", "a/../b", "b"}, {".", "a/b", "a/b"}, {".", "a/b/c/../../d", "a/d"}, {".", "a/b/c/../../../d", "d"}, {".", "a/b/c/../../../../d", "d"}, {".", "a/b/c/d", "a/b/c/d"}, {"", "", "."}, {"", "/", "."}, {"", ".", "."}, {"", "./a", "a"}, {"", "..", "."}, } for _, tc := range testCases { d := Dir(filepath.FromSlash(tc.dir)) if got := filepath.ToSlash(d.resolve(tc.name)); got != tc.want { t.Errorf("dir=%q, name=%q: got %q, want %q", tc.dir, tc.name, got, tc.want) } } } func TestWalk(t *testing.T) { type walkStep struct { name, frag string final bool } testCases := []struct { dir string want []walkStep }{ {"", []walkStep{ {"", "", true}, }}, {"/", []walkStep{ {"", "", true}, }}, {"/a", []walkStep{ {"", "a", true}, }}, {"/a/", []walkStep{ {"", "a", true}, }}, {"/a/b", []walkStep{ {"", "a", false}, {"a", "b", true}, }}, {"/a/b/", []walkStep{ {"", "a", false}, {"a", "b", true}, }}, {"/a/b/c", []walkStep{ {"", "a", false}, {"a", "b", false}, {"b", "c", true}, }}, // The following test case is the one mentioned explicitly // in the method description. {"/foo/bar/x", []walkStep{ {"", "foo", false}, {"foo", "bar", false}, {"bar", "x", true}, }}, } for _, tc := range testCases { fs := NewMemFS().(*memFS) parts := strings.Split(tc.dir, "/") for p := 2; p < len(parts); p++ { d := strings.Join(parts[:p], "/") if err := fs.Mkdir(d, 0666); err != nil { t.Errorf("tc.dir=%q: mkdir: %q: %v", tc.dir, d, err) } } i, prevFrag := 0, "" err := fs.walk("test", tc.dir, func(dir *memFSNode, frag string, final bool) error { got := walkStep{ name: prevFrag, frag: frag, final: final, } want := tc.want[i] if got != want { return fmt.Errorf("got %+v, want %+v", got, want) } i, prevFrag = i+1, frag return nil }) if err != nil { t.Errorf("tc.dir=%q: %v", tc.dir, err) } } } // find appends to ss the names of the named file and its children. It is // analogous to the Unix find command. // // The returned strings are not guaranteed to be in any particular order. func find(ss []string, fs FileSystem, name string) ([]string, error) { stat, err := fs.Stat(name) if err != nil { return nil, err } ss = append(ss, name) if stat.IsDir() { f, err := fs.OpenFile(name, os.O_RDONLY, 0) if err != nil { return nil, err } defer f.Close() children, err := f.Readdir(-1) if err != nil { return nil, err } for _, c := range children { ss, err = find(ss, fs, path.Join(name, c.Name())) if err != nil { return nil, err } } } return ss, nil } func testFS(t *testing.T, fs FileSystem) { errStr := func(err error) string { switch { case os.IsExist(err): return "errExist" case os.IsNotExist(err): return "errNotExist" case err != nil: return "err" } return "ok" } // The non-"find" non-"stat" test cases should change the file system state. The // indentation of the "find"s and "stat"s helps distinguish such test cases. testCases := []string{ " stat / want dir", " stat /a want errNotExist", " stat /d want errNotExist", " stat /d/e want errNotExist", "create /a A want ok", " stat /a want 1", "create /d/e EEE want errNotExist", "mk-dir /a want errExist", "mk-dir /d/m want errNotExist", "mk-dir /d want ok", " stat /d want dir", "create /d/e EEE want ok", " stat /d/e want 3", " find / /a /d /d/e", "create /d/f FFFF want ok", "create /d/g GGGGGGG want ok", "mk-dir /d/m want ok", "mk-dir /d/m want errExist", "create /d/m/p PPPPP want ok", " stat /d/e want 3", " stat /d/f want 4", " stat /d/g want 7", " stat /d/h want errNotExist", " stat /d/m want dir", " stat /d/m/p want 5", " find / /a /d /d/e /d/f /d/g /d/m /d/m/p", "rm-all /d want ok", " stat /a want 1", " stat /d want errNotExist", " stat /d/e want errNotExist", " stat /d/f want errNotExist", " stat /d/g want errNotExist", " stat /d/m want errNotExist", " stat /d/m/p want errNotExist", " find / /a", "mk-dir /d/m want errNotExist", "mk-dir /d want ok", "create /d/f FFFF want ok", "rm-all /d/f want ok", "mk-dir /d/m want ok", "rm-all /z want ok", "rm-all / want err", "create /b BB want ok", " stat / want dir", " stat /a want 1", " stat /b want 2", " stat /c want errNotExist", " stat /d want dir", " stat /d/m want dir", " find / /a /b /d /d/m", "move__ o=F /b /c want ok", " stat /b want errNotExist", " stat /c want 2", " stat /d/m want dir", " stat /d/n want errNotExist", " find / /a /c /d /d/m", "move__ o=F /d/m /d/n want ok", "create /d/n/q QQQQ want ok", " stat /d/m want errNotExist", " stat /d/n want dir", " stat /d/n/q want 4", "move__ o=F /d /d/n/z want err", "move__ o=T /c /d/n/q want ok", " stat /c want errNotExist", " stat /d/n/q want 2", " find / /a /d /d/n /d/n/q", "create /d/n/r RRRRR want ok", "mk-dir /u want ok", "mk-dir /u/v want ok", "move__ o=F /d/n /u want errExist", "create /t TTTTTT want ok", "move__ o=F /d/n /t want errExist", "rm-all /t want ok", "move__ o=F /d/n /t want ok", " stat /d want dir", " stat /d/n want errNotExist", " stat /d/n/r want errNotExist", " stat /t want dir", " stat /t/q want 2", " stat /t/r want 5", " find / /a /d /t /t/q /t/r /u /u/v", "move__ o=F /t / want errExist", "move__ o=T /t /u/v want ok", " stat /u/v/r want 5", "move__ o=F / /z want err", " find / /a /d /u /u/v /u/v/q /u/v/r", " stat /a want 1", " stat /b want errNotExist", " stat /c want errNotExist", " stat /u/v/r want 5", "copy__ o=F d=0 /a /b want ok", "copy__ o=T d=0 /a /c want ok", " stat /a want 1", " stat /b want 1", " stat /c want 1", " stat /u/v/r want 5", "copy__ o=F d=0 /u/v/r /b want errExist", " stat /b want 1", "copy__ o=T d=0 /u/v/r /b want ok", " stat /a want 1", " stat /b want 5", " stat /u/v/r want 5", "rm-all /a want ok", "rm-all /b want ok", "mk-dir /u/v/w want ok", "create /u/v/w/s SSSSSSSS want ok", " stat /d want dir", " stat /d/x want errNotExist", " stat /d/y want errNotExist", " stat /u/v/r want 5", " stat /u/v/w/s want 8", " find / /c /d /u /u/v /u/v/q /u/v/r /u/v/w /u/v/w/s", "copy__ o=T d=0 /u/v /d/x want ok", "copy__ o=T d=∞ /u/v /d/y want ok", "rm-all /u want ok", " stat /d/x want dir", " stat /d/x/q want errNotExist", " stat /d/x/r want errNotExist", " stat /d/x/w want errNotExist", " stat /d/x/w/s want errNotExist", " stat /d/y want dir", " stat /d/y/q want 2", " stat /d/y/r want 5", " stat /d/y/w want dir", " stat /d/y/w/s want 8", " stat /u want errNotExist", " find / /c /d /d/x /d/y /d/y/q /d/y/r /d/y/w /d/y/w/s", "copy__ o=F d=∞ /d/y /d/x want errExist", } for i, tc := range testCases { tc = strings.TrimSpace(tc) j := strings.IndexByte(tc, ' ') if j < 0 { t.Fatalf("test case #%d %q: invalid command", i, tc) } op, arg := tc[:j], tc[j+1:] switch op { default: t.Fatalf("test case #%d %q: invalid operation %q", i, tc, op) case "create": parts := strings.Split(arg, " ") if len(parts) != 4 || parts[2] != "want" { t.Fatalf("test case #%d %q: invalid write", i, tc) } f, opErr := fs.OpenFile(parts[0], os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if got := errStr(opErr); got != parts[3] { t.Fatalf("test case #%d %q: OpenFile: got %q (%v), want %q", i, tc, got, opErr, parts[3]) } if f != nil { if _, err := f.Write([]byte(parts[1])); err != nil { t.Fatalf("test case #%d %q: Write: %v", i, tc, err) } if err := f.Close(); err != nil { t.Fatalf("test case #%d %q: Close: %v", i, tc, err) } } case "find": got, err := find(nil, fs, "/") if err != nil { t.Fatalf("test case #%d %q: find: %v", i, tc, err) } sort.Strings(got) want := strings.Split(arg, " ") if !reflect.DeepEqual(got, want) { t.Fatalf("test case #%d %q:\ngot %s\nwant %s", i, tc, got, want) } case "copy__", "mk-dir", "move__", "rm-all", "stat": nParts := 3 switch op { case "copy__": nParts = 6 case "move__": nParts = 5 } parts := strings.Split(arg, " ") if len(parts) != nParts { t.Fatalf("test case #%d %q: invalid %s", i, tc, op) } got, opErr := "", error(nil) switch op { case "copy__": depth := 0 if parts[1] == "d=∞" { depth = infiniteDepth } _, opErr = copyFiles(fs, parts[2], parts[3], parts[0] == "o=T", depth, 0) case "mk-dir": opErr = fs.Mkdir(parts[0], 0777) case "move__": _, opErr = moveFiles(fs, parts[1], parts[2], parts[0] == "o=T") case "rm-all": opErr = fs.RemoveAll(parts[0]) case "stat": var stat os.FileInfo fileName := parts[0] if stat, opErr = fs.Stat(fileName); opErr == nil { if stat.IsDir() { got = "dir" } else { got = strconv.Itoa(int(stat.Size())) } if fileName == "/" { // For a Dir FileSystem, the virtual file system root maps to a // real file system name like "/tmp/webdav-test012345", which does // not end with "/". We skip such cases. } else if statName := stat.Name(); path.Base(fileName) != statName { t.Fatalf("test case #%d %q: file name %q inconsistent with stat name %q", i, tc, fileName, statName) } } } if got == "" { got = errStr(opErr) } if parts[len(parts)-2] != "want" { t.Fatalf("test case #%d %q: invalid %s", i, tc, op) } if want := parts[len(parts)-1]; got != want { t.Fatalf("test case #%d %q: got %q (%v), want %q", i, tc, got, opErr, want) } } } } func TestDir(t *testing.T) { switch runtime.GOOS { case "nacl": t.Skip("see golang.org/issue/12004") case "plan9": t.Skip("see golang.org/issue/11453") } td, err := ioutil.TempDir("", "webdav-test") if err != nil { t.Fatal(err) } defer os.RemoveAll(td) testFS(t, Dir(td)) } func TestMemFS(t *testing.T) { testFS(t, NewMemFS()) } func TestMemFSRoot(t *testing.T) { fs := NewMemFS() for i := 0; i < 5; i++ { stat, err := fs.Stat("/") if err != nil { t.Fatalf("i=%d: Stat: %v", i, err) } if !stat.IsDir() { t.Fatalf("i=%d: Stat.IsDir is false, want true", i) } f, err := fs.OpenFile("/", os.O_RDONLY, 0) if err != nil { t.Fatalf("i=%d: OpenFile: %v", i, err) } defer f.Close() children, err := f.Readdir(-1) if err != nil { t.Fatalf("i=%d: Readdir: %v", i, err) } if len(children) != i { t.Fatalf("i=%d: got %d children, want %d", i, len(children), i) } if _, err := f.Write(make([]byte, 1)); err == nil { t.Fatalf("i=%d: Write: got nil error, want non-nil", i) } if err := fs.Mkdir(fmt.Sprintf("/dir%d", i), 0777); err != nil { t.Fatalf("i=%d: Mkdir: %v", i, err) } } } func TestMemFileReaddir(t *testing.T) { fs := NewMemFS() if err := fs.Mkdir("/foo", 0777); err != nil { t.Fatalf("Mkdir: %v", err) } readdir := func(count int) ([]os.FileInfo, error) { f, err := fs.OpenFile("/foo", os.O_RDONLY, 0) if err != nil { t.Fatalf("OpenFile: %v", err) } defer f.Close() return f.Readdir(count) } if got, err := readdir(-1); len(got) != 0 || err != nil { t.Fatalf("readdir(-1): got %d fileInfos with err=%v, want 0, ", len(got), err) } if got, err := readdir(+1); len(got) != 0 || err != io.EOF { t.Fatalf("readdir(+1): got %d fileInfos with err=%v, want 0, EOF", len(got), err) } } func TestMemFile(t *testing.T) { testCases := []string{ "wantData ", "wantSize 0", "write abc", "wantData abc", "write de", "wantData abcde", "wantSize 5", "write 5*x", "write 4*y+2*z", "write 3*st", "wantData abcdexxxxxyyyyzzststst", "wantSize 22", "seek set 4 want 4", "write EFG", "wantData abcdEFGxxxyyyyzzststst", "wantSize 22", "seek set 2 want 2", "read cdEF", "read Gx", "seek cur 0 want 8", "seek cur 2 want 10", "seek cur -1 want 9", "write J", "wantData abcdEFGxxJyyyyzzststst", "wantSize 22", "seek cur -4 want 6", "write ghijk", "wantData abcdEFghijkyyyzzststst", "wantSize 22", "read yyyz", "seek cur 0 want 15", "write ", "seek cur 0 want 15", "read ", "seek cur 0 want 15", "seek end -3 want 19", "write ZZ", "wantData abcdEFghijkyyyzzstsZZt", "wantSize 22", "write 4*A", "wantData abcdEFghijkyyyzzstsZZAAAA", "wantSize 25", "seek end 0 want 25", "seek end -5 want 20", "read Z+4*A", "write 5*B", "wantData abcdEFghijkyyyzzstsZZAAAABBBBB", "wantSize 30", "seek end 10 want 40", "write C", "wantData abcdEFghijkyyyzzstsZZAAAABBBBB..........C", "wantSize 41", "write D", "wantData abcdEFghijkyyyzzstsZZAAAABBBBB..........CD", "wantSize 42", "seek set 43 want 43", "write E", "wantData abcdEFghijkyyyzzstsZZAAAABBBBB..........CD.E", "wantSize 44", "seek set 0 want 0", "write 5*123456789_", "wantData 123456789_123456789_123456789_123456789_123456789_", "wantSize 50", "seek cur 0 want 50", "seek cur -99 want err", } const filename = "/foo" fs := NewMemFS() f, err := fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { t.Fatalf("OpenFile: %v", err) } defer f.Close() for i, tc := range testCases { j := strings.IndexByte(tc, ' ') if j < 0 { t.Fatalf("test case #%d %q: invalid command", i, tc) } op, arg := tc[:j], tc[j+1:] // Expand an arg like "3*a+2*b" to "aaabb". parts := strings.Split(arg, "+") for j, part := range parts { if k := strings.IndexByte(part, '*'); k >= 0 { repeatCount, repeatStr := part[:k], part[k+1:] n, err := strconv.Atoi(repeatCount) if err != nil { t.Fatalf("test case #%d %q: invalid repeat count %q", i, tc, repeatCount) } parts[j] = strings.Repeat(repeatStr, n) } } arg = strings.Join(parts, "") switch op { default: t.Fatalf("test case #%d %q: invalid operation %q", i, tc, op) case "read": buf := make([]byte, len(arg)) if _, err := io.ReadFull(f, buf); err != nil { t.Fatalf("test case #%d %q: ReadFull: %v", i, tc, err) } if got := string(buf); got != arg { t.Fatalf("test case #%d %q:\ngot %q\nwant %q", i, tc, got, arg) } case "seek": parts := strings.Split(arg, " ") if len(parts) != 4 { t.Fatalf("test case #%d %q: invalid seek", i, tc) } whence := 0 switch parts[0] { default: t.Fatalf("test case #%d %q: invalid seek whence", i, tc) case "set": whence = os.SEEK_SET case "cur": whence = os.SEEK_CUR case "end": whence = os.SEEK_END } offset, err := strconv.Atoi(parts[1]) if err != nil { t.Fatalf("test case #%d %q: invalid offset %q", i, tc, parts[1]) } if parts[2] != "want" { t.Fatalf("test case #%d %q: invalid seek", i, tc) } if parts[3] == "err" { _, err := f.Seek(int64(offset), whence) if err == nil { t.Fatalf("test case #%d %q: Seek returned nil error, want non-nil", i, tc) } } else { got, err := f.Seek(int64(offset), whence) if err != nil { t.Fatalf("test case #%d %q: Seek: %v", i, tc, err) } want, err := strconv.Atoi(parts[3]) if err != nil { t.Fatalf("test case #%d %q: invalid want %q", i, tc, parts[3]) } if got != int64(want) { t.Fatalf("test case #%d %q: got %d, want %d", i, tc, got, want) } } case "write": n, err := f.Write([]byte(arg)) if err != nil { t.Fatalf("test case #%d %q: write: %v", i, tc, err) } if n != len(arg) { t.Fatalf("test case #%d %q: write returned %d bytes, want %d", i, tc, n, len(arg)) } case "wantData": g, err := fs.OpenFile(filename, os.O_RDONLY, 0666) if err != nil { t.Fatalf("test case #%d %q: OpenFile: %v", i, tc, err) } gotBytes, err := ioutil.ReadAll(g) if err != nil { t.Fatalf("test case #%d %q: ReadAll: %v", i, tc, err) } for i, c := range gotBytes { if c == '\x00' { gotBytes[i] = '.' } } got := string(gotBytes) if got != arg { t.Fatalf("test case #%d %q:\ngot %q\nwant %q", i, tc, got, arg) } if err := g.Close(); err != nil { t.Fatalf("test case #%d %q: Close: %v", i, tc, err) } case "wantSize": n, err := strconv.Atoi(arg) if err != nil { t.Fatalf("test case #%d %q: invalid size %q", i, tc, arg) } fi, err := fs.Stat(filename) if err != nil { t.Fatalf("test case #%d %q: Stat: %v", i, tc, err) } if got, want := fi.Size(), int64(n); got != want { t.Fatalf("test case #%d %q: got %d, want %d", i, tc, got, want) } } } } // TestMemFileWriteAllocs tests that writing N consecutive 1KiB chunks to a // memFile doesn't allocate a new buffer for each of those N times. Otherwise, // calling io.Copy(aMemFile, src) is likely to have quadratic complexity. func TestMemFileWriteAllocs(t *testing.T) { fs := NewMemFS() f, err := fs.OpenFile("/xxx", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { t.Fatalf("OpenFile: %v", err) } defer f.Close() xxx := make([]byte, 1024) for i := range xxx { xxx[i] = 'x' } a := testing.AllocsPerRun(100, func() { f.Write(xxx) }) // AllocsPerRun returns an integral value, so we compare the rounded-down // number to zero. if a > 0 { t.Fatalf("%v allocs per run, want 0", a) } } func BenchmarkMemFileWrite(b *testing.B) { fs := NewMemFS() xxx := make([]byte, 1024) for i := range xxx { xxx[i] = 'x' } b.ResetTimer() for i := 0; i < b.N; i++ { f, err := fs.OpenFile("/xxx", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { b.Fatalf("OpenFile: %v", err) } for j := 0; j < 100; j++ { f.Write(xxx) } if err := f.Close(); err != nil { b.Fatalf("Close: %v", err) } if err := fs.RemoveAll("/xxx"); err != nil { b.Fatalf("RemoveAll: %v", err) } } } func TestCopyMoveProps(t *testing.T) { fs := NewMemFS() create := func(name string) error { f, err := fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { return err } _, wErr := f.Write([]byte("contents")) cErr := f.Close() if wErr != nil { return wErr } return cErr } patch := func(name string, patches ...Proppatch) error { f, err := fs.OpenFile(name, os.O_RDWR, 0666) if err != nil { return err } _, pErr := f.(DeadPropsHolder).Patch(patches) cErr := f.Close() if pErr != nil { return pErr } return cErr } props := func(name string) (map[xml.Name]Property, error) { f, err := fs.OpenFile(name, os.O_RDWR, 0666) if err != nil { return nil, err } m, pErr := f.(DeadPropsHolder).DeadProps() cErr := f.Close() if pErr != nil { return nil, pErr } if cErr != nil { return nil, cErr } return m, nil } p0 := Property{ XMLName: xml.Name{Space: "x:", Local: "boat"}, InnerXML: []byte("pea-green"), } p1 := Property{ XMLName: xml.Name{Space: "x:", Local: "ring"}, InnerXML: []byte("1 shilling"), } p2 := Property{ XMLName: xml.Name{Space: "x:", Local: "spoon"}, InnerXML: []byte("runcible"), } p3 := Property{ XMLName: xml.Name{Space: "x:", Local: "moon"}, InnerXML: []byte("light"), } if err := create("/src"); err != nil { t.Fatalf("create /src: %v", err) } if err := patch("/src", Proppatch{Props: []Property{p0, p1}}); err != nil { t.Fatalf("patch /src +p0 +p1: %v", err) } if _, err := copyFiles(fs, "/src", "/tmp", true, infiniteDepth, 0); err != nil { t.Fatalf("copyFiles /src /tmp: %v", err) } if _, err := moveFiles(fs, "/tmp", "/dst", true); err != nil { t.Fatalf("moveFiles /tmp /dst: %v", err) } if err := patch("/src", Proppatch{Props: []Property{p0}, Remove: true}); err != nil { t.Fatalf("patch /src -p0: %v", err) } if err := patch("/src", Proppatch{Props: []Property{p2}}); err != nil { t.Fatalf("patch /src +p2: %v", err) } if err := patch("/dst", Proppatch{Props: []Property{p1}, Remove: true}); err != nil { t.Fatalf("patch /dst -p1: %v", err) } if err := patch("/dst", Proppatch{Props: []Property{p3}}); err != nil { t.Fatalf("patch /dst +p3: %v", err) } gotSrc, err := props("/src") if err != nil { t.Fatalf("props /src: %v", err) } wantSrc := map[xml.Name]Property{ p1.XMLName: p1, p2.XMLName: p2, } if !reflect.DeepEqual(gotSrc, wantSrc) { t.Fatalf("props /src:\ngot %v\nwant %v", gotSrc, wantSrc) } gotDst, err := props("/dst") if err != nil { t.Fatalf("props /dst: %v", err) } wantDst := map[xml.Name]Property{ p0.XMLName: p0, p3.XMLName: p3, } if !reflect.DeepEqual(gotDst, wantDst) { t.Fatalf("props /dst:\ngot %v\nwant %v", gotDst, wantDst) } } func TestWalkFS(t *testing.T) { testCases := []struct { desc string buildfs []string startAt string depth int walkFn filepath.WalkFunc want []string }{{ "just root", []string{}, "/", infiniteDepth, nil, []string{ "/", }, }, { "infinite walk from root", []string{ "mkdir /a", "mkdir /a/b", "touch /a/b/c", "mkdir /a/d", "mkdir /e", "touch /f", }, "/", infiniteDepth, nil, []string{ "/", "/a", "/a/b", "/a/b/c", "/a/d", "/e", "/f", }, }, { "infinite walk from subdir", []string{ "mkdir /a", "mkdir /a/b", "touch /a/b/c", "mkdir /a/d", "mkdir /e", "touch /f", }, "/a", infiniteDepth, nil, []string{ "/a", "/a/b", "/a/b/c", "/a/d", }, }, { "depth 1 walk from root", []string{ "mkdir /a", "mkdir /a/b", "touch /a/b/c", "mkdir /a/d", "mkdir /e", "touch /f", }, "/", 1, nil, []string{ "/", "/a", "/e", "/f", }, }, { "depth 1 walk from subdir", []string{ "mkdir /a", "mkdir /a/b", "touch /a/b/c", "mkdir /a/b/g", "mkdir /a/b/g/h", "touch /a/b/g/i", "touch /a/b/g/h/j", }, "/a/b", 1, nil, []string{ "/a/b", "/a/b/c", "/a/b/g", }, }, { "depth 0 walk from subdir", []string{ "mkdir /a", "mkdir /a/b", "touch /a/b/c", "mkdir /a/b/g", "mkdir /a/b/g/h", "touch /a/b/g/i", "touch /a/b/g/h/j", }, "/a/b", 0, nil, []string{ "/a/b", }, }, { "infinite walk from file", []string{ "mkdir /a", "touch /a/b", "touch /a/c", }, "/a/b", 0, nil, []string{ "/a/b", }, }, { "infinite walk with skipped subdir", []string{ "mkdir /a", "mkdir /a/b", "touch /a/b/c", "mkdir /a/b/g", "mkdir /a/b/g/h", "touch /a/b/g/i", "touch /a/b/g/h/j", "touch /a/b/z", }, "/", infiniteDepth, func(path string, info os.FileInfo, err error) error { if path == "/a/b/g" { return filepath.SkipDir } return nil }, []string{ "/", "/a", "/a/b", "/a/b/c", "/a/b/z", }, }} for _, tc := range testCases { fs, err := buildTestFS(tc.buildfs) if err != nil { t.Fatalf("%s: cannot create test filesystem: %v", tc.desc, err) } var got []string traceFn := func(path string, info os.FileInfo, err error) error { if tc.walkFn != nil { err = tc.walkFn(path, info, err) if err != nil { return err } } got = append(got, path) return nil } fi, err := fs.Stat(tc.startAt) if err != nil { t.Fatalf("%s: cannot stat: %v", tc.desc, err) } err = walkFS(fs, tc.depth, tc.startAt, fi, traceFn) if err != nil { t.Errorf("%s:\ngot error %v, want nil", tc.desc, err) continue } sort.Strings(got) sort.Strings(tc.want) if !reflect.DeepEqual(got, tc.want) { t.Errorf("%s:\ngot %q\nwant %q", tc.desc, got, tc.want) continue } } } func buildTestFS(buildfs []string) (FileSystem, error) { // TODO: Could this be merged with the build logic in TestFS? fs := NewMemFS() for _, b := range buildfs { op := strings.Split(b, " ") switch op[0] { case "mkdir": err := fs.Mkdir(op[1], os.ModeDir|0777) if err != nil { return nil, err } case "touch": f, err := fs.OpenFile(op[1], os.O_RDWR|os.O_CREATE, 0666) if err != nil { return nil, err } f.Close() case "write": f, err := fs.OpenFile(op[1], os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { return nil, err } _, err = f.Write([]byte(op[2])) f.Close() if err != nil { return nil, err } default: return nil, fmt.Errorf("unknown file operation %q", op[0]) } } return fs, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/if.go000066400000000000000000000075711264464372400226470ustar00rootroot00000000000000// Copyright 2014 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 webdav // The If header is covered by Section 10.4. // http://www.webdav.org/specs/rfc4918.html#HEADER_If import ( "strings" ) // ifHeader is a disjunction (OR) of ifLists. type ifHeader struct { lists []ifList } // ifList is a conjunction (AND) of Conditions, and an optional resource tag. type ifList struct { resourceTag string conditions []Condition } // parseIfHeader parses the "If: foo bar" HTTP header. The httpHeader string // should omit the "If:" prefix and have any "\r\n"s collapsed to a " ", as is // returned by req.Header.Get("If") for a http.Request req. func parseIfHeader(httpHeader string) (h ifHeader, ok bool) { s := strings.TrimSpace(httpHeader) switch tokenType, _, _ := lex(s); tokenType { case '(': return parseNoTagLists(s) case angleTokenType: return parseTaggedLists(s) default: return ifHeader{}, false } } func parseNoTagLists(s string) (h ifHeader, ok bool) { for { l, remaining, ok := parseList(s) if !ok { return ifHeader{}, false } h.lists = append(h.lists, l) if remaining == "" { return h, true } s = remaining } } func parseTaggedLists(s string) (h ifHeader, ok bool) { resourceTag, n := "", 0 for first := true; ; first = false { tokenType, tokenStr, remaining := lex(s) switch tokenType { case angleTokenType: if !first && n == 0 { return ifHeader{}, false } resourceTag, n = tokenStr, 0 s = remaining case '(': n++ l, remaining, ok := parseList(s) if !ok { return ifHeader{}, false } l.resourceTag = resourceTag h.lists = append(h.lists, l) if remaining == "" { return h, true } s = remaining default: return ifHeader{}, false } } } func parseList(s string) (l ifList, remaining string, ok bool) { tokenType, _, s := lex(s) if tokenType != '(' { return ifList{}, "", false } for { tokenType, _, remaining = lex(s) if tokenType == ')' { if len(l.conditions) == 0 { return ifList{}, "", false } return l, remaining, true } c, remaining, ok := parseCondition(s) if !ok { return ifList{}, "", false } l.conditions = append(l.conditions, c) s = remaining } } func parseCondition(s string) (c Condition, remaining string, ok bool) { tokenType, tokenStr, s := lex(s) if tokenType == notTokenType { c.Not = true tokenType, tokenStr, s = lex(s) } switch tokenType { case strTokenType, angleTokenType: c.Token = tokenStr case squareTokenType: c.ETag = tokenStr default: return Condition{}, "", false } return c, s, true } // Single-rune tokens like '(' or ')' have a token type equal to their rune. // All other tokens have a negative token type. const ( errTokenType = rune(-1) eofTokenType = rune(-2) strTokenType = rune(-3) notTokenType = rune(-4) angleTokenType = rune(-5) squareTokenType = rune(-6) ) func lex(s string) (tokenType rune, tokenStr string, remaining string) { // The net/textproto Reader that parses the HTTP header will collapse // Linear White Space that spans multiple "\r\n" lines to a single " ", // so we don't need to look for '\r' or '\n'. for len(s) > 0 && (s[0] == '\t' || s[0] == ' ') { s = s[1:] } if len(s) == 0 { return eofTokenType, "", "" } i := 0 loop: for ; i < len(s); i++ { switch s[i] { case '\t', ' ', '(', ')', '<', '>', '[', ']': break loop } } if i != 0 { tokenStr, remaining = s[:i], s[i:] if tokenStr == "Not" { return notTokenType, "", remaining } return strTokenType, tokenStr, remaining } j := 0 switch s[0] { case '<': j, tokenType = strings.IndexByte(s, '>'), angleTokenType case '[': j, tokenType = strings.IndexByte(s, ']'), squareTokenType default: return rune(s[0]), "", s[1:] } if j < 0 { return errTokenType, "", "" } return tokenType, s[1:j], s[j+1:] } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/if_test.go000066400000000000000000000151521264464372400237000ustar00rootroot00000000000000// Copyright 2014 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 webdav import ( "reflect" "strings" "testing" ) func TestParseIfHeader(t *testing.T) { // The "section x.y.z" test cases come from section x.y.z of the spec at // http://www.webdav.org/specs/rfc4918.html testCases := []struct { desc string input string want ifHeader }{{ "bad: empty", ``, ifHeader{}, }, { "bad: no parens", `foobar`, ifHeader{}, }, { "bad: empty list #1", `()`, ifHeader{}, }, { "bad: empty list #2", `(a) (b c) () (d)`, ifHeader{}, }, { "bad: no list after resource #1", ``, ifHeader{}, }, { "bad: no list after resource #2", ` (a)`, ifHeader{}, }, { "bad: no list after resource #3", ` (a) (b) `, ifHeader{}, }, { "bad: no-tag-list followed by tagged-list", `(a) (b) (c)`, ifHeader{}, }, { "bad: unfinished list", `(a`, ifHeader{}, }, { "bad: unfinished ETag", `([b`, ifHeader{}, }, { "bad: unfinished Notted list", `(Not a`, ifHeader{}, }, { "bad: double Not", `(Not Not a)`, ifHeader{}, }, { "good: one list with a Token", `(a)`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ Token: `a`, }}, }}, }, }, { "good: one list with an ETag", `([a])`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ ETag: `a`, }}, }}, }, }, { "good: one list with three Nots", `(Not a Not b Not [d])`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ Not: true, Token: `a`, }, { Not: true, Token: `b`, }, { Not: true, ETag: `d`, }}, }}, }, }, { "good: two lists", `(a) (b)`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ Token: `a`, }}, }, { conditions: []Condition{{ Token: `b`, }}, }}, }, }, { "good: two Notted lists", `(Not a) (Not b)`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ Not: true, Token: `a`, }}, }, { conditions: []Condition{{ Not: true, Token: `b`, }}, }}, }, }, { "section 7.5.1", ` ()`, ifHeader{ lists: []ifList{{ resourceTag: `http://www.example.com/users/f/fielding/index.html`, conditions: []Condition{{ Token: `urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6`, }}, }}, }, }, { "section 7.5.2 #1", `()`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ Token: `urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf`, }}, }}, }, }, { "section 7.5.2 #2", ` ()`, ifHeader{ lists: []ifList{{ resourceTag: `http://example.com/locked/`, conditions: []Condition{{ Token: `urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf`, }}, }}, }, }, { "section 7.5.2 #3", ` ()`, ifHeader{ lists: []ifList{{ resourceTag: `http://example.com/locked/member`, conditions: []Condition{{ Token: `urn:uuid:150852e2-3847-42d5-8cbe-0f4f296f26cf`, }}, }}, }, }, { "section 9.9.6", `() ()`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ Token: `urn:uuid:fe184f2e-6eec-41d0-c765-01adc56e6bb4`, }}, }, { conditions: []Condition{{ Token: `urn:uuid:e454f3f3-acdc-452a-56c7-00a5c91e4b77`, }}, }}, }, }, { "section 9.10.8", `()`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ Token: `urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4`, }}, }}, }, }, { "section 10.4.6", `( ["I am an ETag"]) (["I am another ETag"])`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`, }, { ETag: `"I am an ETag"`, }}, }, { conditions: []Condition{{ ETag: `"I am another ETag"`, }}, }}, }, }, { "section 10.4.7", `(Not )`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ Not: true, Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`, }, { Token: `urn:uuid:58f202ac-22cf-11d1-b12d-002035b29092`, }}, }}, }, }, { "section 10.4.8", `() (Not )`, ifHeader{ lists: []ifList{{ conditions: []Condition{{ Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`, }}, }, { conditions: []Condition{{ Not: true, Token: `DAV:no-lock`, }}, }}, }, }, { "section 10.4.9", ` ( [W/"A weak ETag"]) (["strong ETag"])`, ifHeader{ lists: []ifList{{ resourceTag: `/resource1`, conditions: []Condition{{ Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`, }, { ETag: `W/"A weak ETag"`, }}, }, { resourceTag: `/resource1`, conditions: []Condition{{ ETag: `"strong ETag"`, }}, }}, }, }, { "section 10.4.10", ` ()`, ifHeader{ lists: []ifList{{ resourceTag: `http://www.example.com/specs/`, conditions: []Condition{{ Token: `urn:uuid:181d4fae-7d8c-11d0-a765-00a0c91e6bf2`, }}, }}, }, }, { "section 10.4.11 #1", ` (["4217"])`, ifHeader{ lists: []ifList{{ resourceTag: `/specs/rfc2518.doc`, conditions: []Condition{{ ETag: `"4217"`, }}, }}, }, }, { "section 10.4.11 #2", ` (Not ["4217"])`, ifHeader{ lists: []ifList{{ resourceTag: `/specs/rfc2518.doc`, conditions: []Condition{{ Not: true, ETag: `"4217"`, }}, }}, }, }} for _, tc := range testCases { got, ok := parseIfHeader(strings.Replace(tc.input, "\n", "", -1)) if gotEmpty := reflect.DeepEqual(got, ifHeader{}); gotEmpty == ok { t.Errorf("%s: should be different: empty header == %t, ok == %t", tc.desc, gotEmpty, ok) continue } if !reflect.DeepEqual(got, tc.want) { t.Errorf("%s:\ngot %v\nwant %v", tc.desc, got, tc.want) continue } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/000077500000000000000000000000001264464372400235245ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/xml/000077500000000000000000000000001264464372400243245ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/xml/README000066400000000000000000000006711264464372400252100ustar00rootroot00000000000000This is a fork of the encoding/xml package at ca1d6c4, the last commit before https://go.googlesource.com/go/+/c0d6d33 "encoding/xml: restore Go 1.4 name space behavior" made late in the lead-up to the Go 1.5 release. The list of encoding/xml changes is at https://go.googlesource.com/go/+log/master/src/encoding/xml This fork is temporary, and I (nigeltao) expect to revert it after Go 1.6 is released. See http://golang.org/issue/11841 golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/xml/atom_test.go000066400000000000000000000031261264464372400266540ustar00rootroot00000000000000// 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 xml import "time" var atomValue = &Feed{ XMLName: Name{"http://www.w3.org/2005/Atom", "feed"}, Title: "Example Feed", Link: []Link{{Href: "http://example.org/"}}, Updated: ParseTime("2003-12-13T18:30:02Z"), Author: Person{Name: "John Doe"}, Id: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6", Entry: []Entry{ { Title: "Atom-Powered Robots Run Amok", Link: []Link{{Href: "http://example.org/2003/12/13/atom03"}}, Id: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a", Updated: ParseTime("2003-12-13T18:30:02Z"), Summary: NewText("Some text."), }, }, } var atomXml = `` + `` + `Example Feed` + `urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6` + `` + `John Doe` + `` + `Atom-Powered Robots Run Amok` + `urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a` + `` + `2003-12-13T18:30:02Z` + `` + `Some text.` + `` + `` func ParseTime(str string) time.Time { t, err := time.Parse(time.RFC3339, str) if err != nil { panic(err) } return t } func NewText(text string) Text { return Text{ Body: text, } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/xml/example_test.go000066400000000000000000000073371264464372400273570ustar00rootroot00000000000000// Copyright 2012 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 xml_test import ( "encoding/xml" "fmt" "os" ) func ExampleMarshalIndent() { type Address struct { City, State string } type Person struct { XMLName xml.Name `xml:"person"` Id int `xml:"id,attr"` FirstName string `xml:"name>first"` LastName string `xml:"name>last"` Age int `xml:"age"` Height float32 `xml:"height,omitempty"` Married bool Address Comment string `xml:",comment"` } v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42} v.Comment = " Need more details. " v.Address = Address{"Hanga Roa", "Easter Island"} output, err := xml.MarshalIndent(v, " ", " ") if err != nil { fmt.Printf("error: %v\n", err) } os.Stdout.Write(output) // Output: // // // John // Doe // // 42 // false // Hanga Roa // Easter Island // // } func ExampleEncoder() { type Address struct { City, State string } type Person struct { XMLName xml.Name `xml:"person"` Id int `xml:"id,attr"` FirstName string `xml:"name>first"` LastName string `xml:"name>last"` Age int `xml:"age"` Height float32 `xml:"height,omitempty"` Married bool Address Comment string `xml:",comment"` } v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42} v.Comment = " Need more details. " v.Address = Address{"Hanga Roa", "Easter Island"} enc := xml.NewEncoder(os.Stdout) enc.Indent(" ", " ") if err := enc.Encode(v); err != nil { fmt.Printf("error: %v\n", err) } // Output: // // // John // Doe // // 42 // false // Hanga Roa // Easter Island // // } // This example demonstrates unmarshaling an XML excerpt into a value with // some preset fields. Note that the Phone field isn't modified and that // the XML element is ignored. Also, the Groups field is assigned // considering the element path provided in its tag. func ExampleUnmarshal() { type Email struct { Where string `xml:"where,attr"` Addr string } type Address struct { City, State string } type Result struct { XMLName xml.Name `xml:"Person"` Name string `xml:"FullName"` Phone string Email []Email Groups []string `xml:"Group>Value"` Address } v := Result{Name: "none", Phone: "none"} data := ` Grace R. Emlin Example Inc. gre@example.com gre@work.com Friends Squash Hanga Roa Easter Island ` err := xml.Unmarshal([]byte(data), &v) if err != nil { fmt.Printf("error: %v", err) return } fmt.Printf("XMLName: %#v\n", v.XMLName) fmt.Printf("Name: %q\n", v.Name) fmt.Printf("Phone: %q\n", v.Phone) fmt.Printf("Email: %v\n", v.Email) fmt.Printf("Groups: %v\n", v.Groups) fmt.Printf("Address: %v\n", v.Address) // Output: // XMLName: xml.Name{Space:"", Local:"Person"} // Name: "Grace R. Emlin" // Phone: "none" // Email: [{home gre@example.com} {work gre@work.com}] // Groups: [Friends Squash] // Address: {Hanga Roa Easter Island} } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/xml/marshal.go000066400000000000000000001060621264464372400263070ustar00rootroot00000000000000// 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 xml import ( "bufio" "bytes" "encoding" "fmt" "io" "reflect" "strconv" "strings" ) const ( // A generic XML header suitable for use with the output of Marshal. // This is not automatically added to any output of this package, // it is provided as a convenience. Header = `` + "\n" ) // Marshal returns the XML encoding of v. // // Marshal handles an array or slice by marshalling each of the elements. // Marshal handles a pointer by marshalling the value it points at or, if the // pointer is nil, by writing nothing. Marshal handles an interface value by // marshalling the value it contains or, if the interface value is nil, by // writing nothing. Marshal handles all other data by writing one or more XML // elements containing the data. // // The name for the XML elements is taken from, in order of preference: // - the tag on the XMLName field, if the data is a struct // - the value of the XMLName field of type xml.Name // - the tag of the struct field used to obtain the data // - the name of the struct field used to obtain the data // - the name of the marshalled type // // The XML element for a struct contains marshalled elements for each of the // exported fields of the struct, with these exceptions: // - the XMLName field, described above, is omitted. // - a field with tag "-" is omitted. // - a field with tag "name,attr" becomes an attribute with // the given name in the XML element. // - a field with tag ",attr" becomes an attribute with the // field name in the XML element. // - a field with tag ",chardata" is written as character data, // not as an XML element. // - a field with tag ",innerxml" is written verbatim, not subject // to the usual marshalling procedure. // - a field with tag ",comment" is written as an XML comment, not // subject to the usual marshalling procedure. It must not contain // the "--" string within it. // - a field with a tag including the "omitempty" option is omitted // if the field value is empty. The empty values are false, 0, any // nil pointer or interface value, and any array, slice, map, or // string of length zero. // - an anonymous struct field is handled as if the fields of its // value were part of the outer struct. // // If a field uses a tag "a>b>c", then the element c will be nested inside // parent elements a and b. Fields that appear next to each other that name // the same parent will be enclosed in one XML element. // // See MarshalIndent for an example. // // Marshal will return an error if asked to marshal a channel, function, or map. func Marshal(v interface{}) ([]byte, error) { var b bytes.Buffer if err := NewEncoder(&b).Encode(v); err != nil { return nil, err } return b.Bytes(), nil } // Marshaler is the interface implemented by objects that can marshal // themselves into valid XML elements. // // MarshalXML encodes the receiver as zero or more XML elements. // By convention, arrays or slices are typically encoded as a sequence // of elements, one per entry. // Using start as the element tag is not required, but doing so // will enable Unmarshal to match the XML elements to the correct // struct field. // One common implementation strategy is to construct a separate // value with a layout corresponding to the desired XML and then // to encode it using e.EncodeElement. // Another common strategy is to use repeated calls to e.EncodeToken // to generate the XML output one token at a time. // The sequence of encoded tokens must make up zero or more valid // XML elements. type Marshaler interface { MarshalXML(e *Encoder, start StartElement) error } // MarshalerAttr is the interface implemented by objects that can marshal // themselves into valid XML attributes. // // MarshalXMLAttr returns an XML attribute with the encoded value of the receiver. // Using name as the attribute name is not required, but doing so // will enable Unmarshal to match the attribute to the correct // struct field. // If MarshalXMLAttr returns the zero attribute Attr{}, no attribute // will be generated in the output. // MarshalXMLAttr is used only for struct fields with the // "attr" option in the field tag. type MarshalerAttr interface { MarshalXMLAttr(name Name) (Attr, error) } // MarshalIndent works like Marshal, but each XML element begins on a new // indented line that starts with prefix and is followed by one or more // copies of indent according to the nesting depth. func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { var b bytes.Buffer enc := NewEncoder(&b) enc.Indent(prefix, indent) if err := enc.Encode(v); err != nil { return nil, err } return b.Bytes(), nil } // An Encoder writes XML data to an output stream. type Encoder struct { p printer } // NewEncoder returns a new encoder that writes to w. func NewEncoder(w io.Writer) *Encoder { e := &Encoder{printer{Writer: bufio.NewWriter(w)}} e.p.encoder = e return e } // Indent sets the encoder to generate XML in which each element // begins on a new indented line that starts with prefix and is followed by // one or more copies of indent according to the nesting depth. func (enc *Encoder) Indent(prefix, indent string) { enc.p.prefix = prefix enc.p.indent = indent } // Encode writes the XML encoding of v to the stream. // // See the documentation for Marshal for details about the conversion // of Go values to XML. // // Encode calls Flush before returning. func (enc *Encoder) Encode(v interface{}) error { err := enc.p.marshalValue(reflect.ValueOf(v), nil, nil) if err != nil { return err } return enc.p.Flush() } // EncodeElement writes the XML encoding of v to the stream, // using start as the outermost tag in the encoding. // // See the documentation for Marshal for details about the conversion // of Go values to XML. // // EncodeElement calls Flush before returning. func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error { err := enc.p.marshalValue(reflect.ValueOf(v), nil, &start) if err != nil { return err } return enc.p.Flush() } var ( begComment = []byte("") endProcInst = []byte("?>") endDirective = []byte(">") ) // EncodeToken writes the given XML token to the stream. // It returns an error if StartElement and EndElement tokens are not // properly matched. // // EncodeToken does not call Flush, because usually it is part of a // larger operation such as Encode or EncodeElement (or a custom // Marshaler's MarshalXML invoked during those), and those will call // Flush when finished. Callers that create an Encoder and then invoke // EncodeToken directly, without using Encode or EncodeElement, need to // call Flush when finished to ensure that the XML is written to the // underlying writer. // // EncodeToken allows writing a ProcInst with Target set to "xml" only // as the first token in the stream. // // When encoding a StartElement holding an XML namespace prefix // declaration for a prefix that is not already declared, contained // elements (including the StartElement itself) will use the declared // prefix when encoding names with matching namespace URIs. func (enc *Encoder) EncodeToken(t Token) error { p := &enc.p switch t := t.(type) { case StartElement: if err := p.writeStart(&t); err != nil { return err } case EndElement: if err := p.writeEnd(t.Name); err != nil { return err } case CharData: escapeText(p, t, false) case Comment: if bytes.Contains(t, endComment) { return fmt.Errorf("xml: EncodeToken of Comment containing --> marker") } p.WriteString("") return p.cachedWriteError() case ProcInst: // First token to be encoded which is also a ProcInst with target of xml // is the xml declaration. The only ProcInst where target of xml is allowed. if t.Target == "xml" && p.Buffered() != 0 { return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded") } if !isNameString(t.Target) { return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target") } if bytes.Contains(t.Inst, endProcInst) { return fmt.Errorf("xml: EncodeToken of ProcInst containing ?> marker") } p.WriteString(" 0 { p.WriteByte(' ') p.Write(t.Inst) } p.WriteString("?>") case Directive: if !isValidDirective(t) { return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers") } p.WriteString("") default: return fmt.Errorf("xml: EncodeToken of invalid token type") } return p.cachedWriteError() } // isValidDirective reports whether dir is a valid directive text, // meaning angle brackets are matched, ignoring comments and strings. func isValidDirective(dir Directive) bool { var ( depth int inquote uint8 incomment bool ) for i, c := range dir { switch { case incomment: if c == '>' { if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) { incomment = false } } // Just ignore anything in comment case inquote != 0: if c == inquote { inquote = 0 } // Just ignore anything within quotes case c == '\'' || c == '"': inquote = c case c == '<': if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) { incomment = true } else { depth++ } case c == '>': if depth == 0 { return false } depth-- } } return depth == 0 && inquote == 0 && !incomment } // Flush flushes any buffered XML to the underlying writer. // See the EncodeToken documentation for details about when it is necessary. func (enc *Encoder) Flush() error { return enc.p.Flush() } type printer struct { *bufio.Writer encoder *Encoder seq int indent string prefix string depth int indentedIn bool putNewline bool defaultNS string attrNS map[string]string // map prefix -> name space attrPrefix map[string]string // map name space -> prefix prefixes []printerPrefix tags []Name } // printerPrefix holds a namespace undo record. // When an element is popped, the prefix record // is set back to the recorded URL. The empty // prefix records the URL for the default name space. // // The start of an element is recorded with an element // that has mark=true. type printerPrefix struct { prefix string url string mark bool } func (p *printer) prefixForNS(url string, isAttr bool) string { // The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml" // and must be referred to that way. // (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns", // but users should not be trying to use that one directly - that's our job.) if url == xmlURL { return "xml" } if !isAttr && url == p.defaultNS { // We can use the default name space. return "" } return p.attrPrefix[url] } // defineNS pushes any namespace definition found in the given attribute. // If ignoreNonEmptyDefault is true, an xmlns="nonempty" // attribute will be ignored. func (p *printer) defineNS(attr Attr, ignoreNonEmptyDefault bool) error { var prefix string if attr.Name.Local == "xmlns" { if attr.Name.Space != "" && attr.Name.Space != "xml" && attr.Name.Space != xmlURL { return fmt.Errorf("xml: cannot redefine xmlns attribute prefix") } } else if attr.Name.Space == "xmlns" && attr.Name.Local != "" { prefix = attr.Name.Local if attr.Value == "" { // Technically, an empty XML namespace is allowed for an attribute. // From http://www.w3.org/TR/xml-names11/#scoping-defaulting: // // The attribute value in a namespace declaration for a prefix may be // empty. This has the effect, within the scope of the declaration, of removing // any association of the prefix with a namespace name. // // However our namespace prefixes here are used only as hints. There's // no need to respect the removal of a namespace prefix, so we ignore it. return nil } } else { // Ignore: it's not a namespace definition return nil } if prefix == "" { if attr.Value == p.defaultNS { // No need for redefinition. return nil } if attr.Value != "" && ignoreNonEmptyDefault { // We have an xmlns="..." value but // it can't define a name space in this context, // probably because the element has an empty // name space. In this case, we just ignore // the name space declaration. return nil } } else if _, ok := p.attrPrefix[attr.Value]; ok { // There's already a prefix for the given name space, // so use that. This prevents us from // having two prefixes for the same name space // so attrNS and attrPrefix can remain bijective. return nil } p.pushPrefix(prefix, attr.Value) return nil } // createNSPrefix creates a name space prefix attribute // to use for the given name space, defining a new prefix // if necessary. // If isAttr is true, the prefix is to be created for an attribute // prefix, which means that the default name space cannot // be used. func (p *printer) createNSPrefix(url string, isAttr bool) { if _, ok := p.attrPrefix[url]; ok { // We already have a prefix for the given URL. return } switch { case !isAttr && url == p.defaultNS: // We can use the default name space. return case url == "": // The only way we can encode names in the empty // name space is by using the default name space, // so we must use that. if p.defaultNS != "" { // The default namespace is non-empty, so we // need to set it to empty. p.pushPrefix("", "") } return case url == xmlURL: return } // TODO If the URL is an existing prefix, we could // use it as is. That would enable the // marshaling of elements that had been unmarshaled // and with a name space prefix that was not found. // although technically it would be incorrect. // Pick a name. We try to use the final element of the path // but fall back to _. prefix := strings.TrimRight(url, "/") if i := strings.LastIndex(prefix, "/"); i >= 0 { prefix = prefix[i+1:] } if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") { prefix = "_" } if strings.HasPrefix(prefix, "xml") { // xmlanything is reserved. prefix = "_" + prefix } if p.attrNS[prefix] != "" { // Name is taken. Find a better one. for p.seq++; ; p.seq++ { if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" { prefix = id break } } } p.pushPrefix(prefix, url) } // writeNamespaces writes xmlns attributes for all the // namespace prefixes that have been defined in // the current element. func (p *printer) writeNamespaces() { for i := len(p.prefixes) - 1; i >= 0; i-- { prefix := p.prefixes[i] if prefix.mark { return } p.WriteString(" ") if prefix.prefix == "" { // Default name space. p.WriteString(`xmlns="`) } else { p.WriteString("xmlns:") p.WriteString(prefix.prefix) p.WriteString(`="`) } EscapeText(p, []byte(p.nsForPrefix(prefix.prefix))) p.WriteString(`"`) } } // pushPrefix pushes a new prefix on the prefix stack // without checking to see if it is already defined. func (p *printer) pushPrefix(prefix, url string) { p.prefixes = append(p.prefixes, printerPrefix{ prefix: prefix, url: p.nsForPrefix(prefix), }) p.setAttrPrefix(prefix, url) } // nsForPrefix returns the name space for the given // prefix. Note that this is not valid for the // empty attribute prefix, which always has an empty // name space. func (p *printer) nsForPrefix(prefix string) string { if prefix == "" { return p.defaultNS } return p.attrNS[prefix] } // markPrefix marks the start of an element on the prefix // stack. func (p *printer) markPrefix() { p.prefixes = append(p.prefixes, printerPrefix{ mark: true, }) } // popPrefix pops all defined prefixes for the current // element. func (p *printer) popPrefix() { for len(p.prefixes) > 0 { prefix := p.prefixes[len(p.prefixes)-1] p.prefixes = p.prefixes[:len(p.prefixes)-1] if prefix.mark { break } p.setAttrPrefix(prefix.prefix, prefix.url) } } // setAttrPrefix sets an attribute name space prefix. // If url is empty, the attribute is removed. // If prefix is empty, the default name space is set. func (p *printer) setAttrPrefix(prefix, url string) { if prefix == "" { p.defaultNS = url return } if url == "" { delete(p.attrPrefix, p.attrNS[prefix]) delete(p.attrNS, prefix) return } if p.attrPrefix == nil { // Need to define a new name space. p.attrPrefix = make(map[string]string) p.attrNS = make(map[string]string) } // Remove any old prefix value. This is OK because we maintain a // strict one-to-one mapping between prefix and URL (see // defineNS) delete(p.attrPrefix, p.attrNS[prefix]) p.attrPrefix[url] = prefix p.attrNS[prefix] = url } var ( marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() marshalerAttrType = reflect.TypeOf((*MarshalerAttr)(nil)).Elem() textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() ) // marshalValue writes one or more XML elements representing val. // If val was obtained from a struct field, finfo must have its details. func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplate *StartElement) error { if startTemplate != nil && startTemplate.Name.Local == "" { return fmt.Errorf("xml: EncodeElement of StartElement with missing name") } if !val.IsValid() { return nil } if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) { return nil } // Drill into interfaces and pointers. // This can turn into an infinite loop given a cyclic chain, // but it matches the Go 1 behavior. for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr { if val.IsNil() { return nil } val = val.Elem() } kind := val.Kind() typ := val.Type() // Check for marshaler. if val.CanInterface() && typ.Implements(marshalerType) { return p.marshalInterface(val.Interface().(Marshaler), p.defaultStart(typ, finfo, startTemplate)) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(marshalerType) { return p.marshalInterface(pv.Interface().(Marshaler), p.defaultStart(pv.Type(), finfo, startTemplate)) } } // Check for text marshaler. if val.CanInterface() && typ.Implements(textMarshalerType) { return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), p.defaultStart(typ, finfo, startTemplate)) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), p.defaultStart(pv.Type(), finfo, startTemplate)) } } // Slices and arrays iterate over the elements. They do not have an enclosing tag. if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 { for i, n := 0, val.Len(); i < n; i++ { if err := p.marshalValue(val.Index(i), finfo, startTemplate); err != nil { return err } } return nil } tinfo, err := getTypeInfo(typ) if err != nil { return err } // Create start element. // Precedence for the XML element name is: // 0. startTemplate // 1. XMLName field in underlying struct; // 2. field name/tag in the struct field; and // 3. type name var start StartElement // explicitNS records whether the element's name space has been // explicitly set (for example an XMLName field). explicitNS := false if startTemplate != nil { start.Name = startTemplate.Name explicitNS = true start.Attr = append(start.Attr, startTemplate.Attr...) } else if tinfo.xmlname != nil { xmlname := tinfo.xmlname if xmlname.name != "" { start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name } else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" { start.Name = v } explicitNS = true } if start.Name.Local == "" && finfo != nil { start.Name.Local = finfo.name if finfo.xmlns != "" { start.Name.Space = finfo.xmlns explicitNS = true } } if start.Name.Local == "" { name := typ.Name() if name == "" { return &UnsupportedTypeError{typ} } start.Name.Local = name } // defaultNS records the default name space as set by a xmlns="..." // attribute. We don't set p.defaultNS because we want to let // the attribute writing code (in p.defineNS) be solely responsible // for maintaining that. defaultNS := p.defaultNS // Attributes for i := range tinfo.fields { finfo := &tinfo.fields[i] if finfo.flags&fAttr == 0 { continue } attr, err := p.fieldAttr(finfo, val) if err != nil { return err } if attr.Name.Local == "" { continue } start.Attr = append(start.Attr, attr) if attr.Name.Space == "" && attr.Name.Local == "xmlns" { defaultNS = attr.Value } } if !explicitNS { // Historic behavior: elements use the default name space // they are contained in by default. start.Name.Space = defaultNS } // Historic behaviour: an element that's in a namespace sets // the default namespace for all elements contained within it. start.setDefaultNamespace() if err := p.writeStart(&start); err != nil { return err } if val.Kind() == reflect.Struct { err = p.marshalStruct(tinfo, val) } else { s, b, err1 := p.marshalSimple(typ, val) if err1 != nil { err = err1 } else if b != nil { EscapeText(p, b) } else { p.EscapeString(s) } } if err != nil { return err } if err := p.writeEnd(start.Name); err != nil { return err } return p.cachedWriteError() } // fieldAttr returns the attribute of the given field. // If the returned attribute has an empty Name.Local, // it should not be used. // The given value holds the value containing the field. func (p *printer) fieldAttr(finfo *fieldInfo, val reflect.Value) (Attr, error) { fv := finfo.value(val) name := Name{Space: finfo.xmlns, Local: finfo.name} if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) { return Attr{}, nil } if fv.Kind() == reflect.Interface && fv.IsNil() { return Attr{}, nil } if fv.CanInterface() && fv.Type().Implements(marshalerAttrType) { attr, err := fv.Interface().(MarshalerAttr).MarshalXMLAttr(name) return attr, err } if fv.CanAddr() { pv := fv.Addr() if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) { attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name) return attr, err } } if fv.CanInterface() && fv.Type().Implements(textMarshalerType) { text, err := fv.Interface().(encoding.TextMarshaler).MarshalText() if err != nil { return Attr{}, err } return Attr{name, string(text)}, nil } if fv.CanAddr() { pv := fv.Addr() if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { text, err := pv.Interface().(encoding.TextMarshaler).MarshalText() if err != nil { return Attr{}, err } return Attr{name, string(text)}, nil } } // Dereference or skip nil pointer, interface values. switch fv.Kind() { case reflect.Ptr, reflect.Interface: if fv.IsNil() { return Attr{}, nil } fv = fv.Elem() } s, b, err := p.marshalSimple(fv.Type(), fv) if err != nil { return Attr{}, err } if b != nil { s = string(b) } return Attr{name, s}, nil } // defaultStart returns the default start element to use, // given the reflect type, field info, and start template. func (p *printer) defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement { var start StartElement // Precedence for the XML element name is as above, // except that we do not look inside structs for the first field. if startTemplate != nil { start.Name = startTemplate.Name start.Attr = append(start.Attr, startTemplate.Attr...) } else if finfo != nil && finfo.name != "" { start.Name.Local = finfo.name start.Name.Space = finfo.xmlns } else if typ.Name() != "" { start.Name.Local = typ.Name() } else { // Must be a pointer to a named type, // since it has the Marshaler methods. start.Name.Local = typ.Elem().Name() } // Historic behaviour: elements use the name space of // the element they are contained in by default. if start.Name.Space == "" { start.Name.Space = p.defaultNS } start.setDefaultNamespace() return start } // marshalInterface marshals a Marshaler interface value. func (p *printer) marshalInterface(val Marshaler, start StartElement) error { // Push a marker onto the tag stack so that MarshalXML // cannot close the XML tags that it did not open. p.tags = append(p.tags, Name{}) n := len(p.tags) err := val.MarshalXML(p.encoder, start) if err != nil { return err } // Make sure MarshalXML closed all its tags. p.tags[n-1] is the mark. if len(p.tags) > n { return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local) } p.tags = p.tags[:n-1] return nil } // marshalTextInterface marshals a TextMarshaler interface value. func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error { if err := p.writeStart(&start); err != nil { return err } text, err := val.MarshalText() if err != nil { return err } EscapeText(p, text) return p.writeEnd(start.Name) } // writeStart writes the given start element. func (p *printer) writeStart(start *StartElement) error { if start.Name.Local == "" { return fmt.Errorf("xml: start tag with no name") } p.tags = append(p.tags, start.Name) p.markPrefix() // Define any name spaces explicitly declared in the attributes. // We do this as a separate pass so that explicitly declared prefixes // will take precedence over implicitly declared prefixes // regardless of the order of the attributes. ignoreNonEmptyDefault := start.Name.Space == "" for _, attr := range start.Attr { if err := p.defineNS(attr, ignoreNonEmptyDefault); err != nil { return err } } // Define any new name spaces implied by the attributes. for _, attr := range start.Attr { name := attr.Name // From http://www.w3.org/TR/xml-names11/#defaulting // "Default namespace declarations do not apply directly // to attribute names; the interpretation of unprefixed // attributes is determined by the element on which they // appear." // This means we don't need to create a new namespace // when an attribute name space is empty. if name.Space != "" && !name.isNamespace() { p.createNSPrefix(name.Space, true) } } p.createNSPrefix(start.Name.Space, false) p.writeIndent(1) p.WriteByte('<') p.writeName(start.Name, false) p.writeNamespaces() for _, attr := range start.Attr { name := attr.Name if name.Local == "" || name.isNamespace() { // Namespaces have already been written by writeNamespaces above. continue } p.WriteByte(' ') p.writeName(name, true) p.WriteString(`="`) p.EscapeString(attr.Value) p.WriteByte('"') } p.WriteByte('>') return nil } // writeName writes the given name. It assumes // that p.createNSPrefix(name) has already been called. func (p *printer) writeName(name Name, isAttr bool) { if prefix := p.prefixForNS(name.Space, isAttr); prefix != "" { p.WriteString(prefix) p.WriteByte(':') } p.WriteString(name.Local) } func (p *printer) writeEnd(name Name) error { if name.Local == "" { return fmt.Errorf("xml: end tag with no name") } if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" { return fmt.Errorf("xml: end tag without start tag", name.Local) } if top := p.tags[len(p.tags)-1]; top != name { if top.Local != name.Local { return fmt.Errorf("xml: end tag does not match start tag <%s>", name.Local, top.Local) } return fmt.Errorf("xml: end tag in namespace %s does not match start tag <%s> in namespace %s", name.Local, name.Space, top.Local, top.Space) } p.tags = p.tags[:len(p.tags)-1] p.writeIndent(-1) p.WriteByte('<') p.WriteByte('/') p.writeName(name, false) p.WriteByte('>') p.popPrefix() return nil } func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) { switch val.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return strconv.FormatInt(val.Int(), 10), nil, nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return strconv.FormatUint(val.Uint(), 10), nil, nil case reflect.Float32, reflect.Float64: return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil case reflect.String: return val.String(), nil, nil case reflect.Bool: return strconv.FormatBool(val.Bool()), nil, nil case reflect.Array: if typ.Elem().Kind() != reflect.Uint8 { break } // [...]byte var bytes []byte if val.CanAddr() { bytes = val.Slice(0, val.Len()).Bytes() } else { bytes = make([]byte, val.Len()) reflect.Copy(reflect.ValueOf(bytes), val) } return "", bytes, nil case reflect.Slice: if typ.Elem().Kind() != reflect.Uint8 { break } // []byte return "", val.Bytes(), nil } return "", nil, &UnsupportedTypeError{typ} } var ddBytes = []byte("--") func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { s := parentStack{p: p} for i := range tinfo.fields { finfo := &tinfo.fields[i] if finfo.flags&fAttr != 0 { continue } vf := finfo.value(val) // Dereference or skip nil pointer, interface values. switch vf.Kind() { case reflect.Ptr, reflect.Interface: if !vf.IsNil() { vf = vf.Elem() } } switch finfo.flags & fMode { case fCharData: if err := s.setParents(&noField, reflect.Value{}); err != nil { return err } if vf.CanInterface() && vf.Type().Implements(textMarshalerType) { data, err := vf.Interface().(encoding.TextMarshaler).MarshalText() if err != nil { return err } Escape(p, data) continue } if vf.CanAddr() { pv := vf.Addr() if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { data, err := pv.Interface().(encoding.TextMarshaler).MarshalText() if err != nil { return err } Escape(p, data) continue } } var scratch [64]byte switch vf.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: Escape(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: Escape(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10)) case reflect.Float32, reflect.Float64: Escape(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits())) case reflect.Bool: Escape(p, strconv.AppendBool(scratch[:0], vf.Bool())) case reflect.String: if err := EscapeText(p, []byte(vf.String())); err != nil { return err } case reflect.Slice: if elem, ok := vf.Interface().([]byte); ok { if err := EscapeText(p, elem); err != nil { return err } } } continue case fComment: if err := s.setParents(&noField, reflect.Value{}); err != nil { return err } k := vf.Kind() if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) { return fmt.Errorf("xml: bad type for comment field of %s", val.Type()) } if vf.Len() == 0 { continue } p.writeIndent(0) p.WriteString("" is invalid grammar. Make it "- -->" p.WriteByte(' ') } p.WriteString("-->") continue case fInnerXml: iface := vf.Interface() switch raw := iface.(type) { case []byte: p.Write(raw) continue case string: p.WriteString(raw) continue } case fElement, fElement | fAny: if err := s.setParents(finfo, vf); err != nil { return err } } if err := p.marshalValue(vf, finfo, nil); err != nil { return err } } if err := s.setParents(&noField, reflect.Value{}); err != nil { return err } return p.cachedWriteError() } var noField fieldInfo // return the bufio Writer's cached write error func (p *printer) cachedWriteError() error { _, err := p.Write(nil) return err } func (p *printer) writeIndent(depthDelta int) { if len(p.prefix) == 0 && len(p.indent) == 0 { return } if depthDelta < 0 { p.depth-- if p.indentedIn { p.indentedIn = false return } p.indentedIn = false } if p.putNewline { p.WriteByte('\n') } else { p.putNewline = true } if len(p.prefix) > 0 { p.WriteString(p.prefix) } if len(p.indent) > 0 { for i := 0; i < p.depth; i++ { p.WriteString(p.indent) } } if depthDelta > 0 { p.depth++ p.indentedIn = true } } type parentStack struct { p *printer xmlns string parents []string } // setParents sets the stack of current parents to those found in finfo. // It only writes the start elements if vf holds a non-nil value. // If finfo is &noField, it pops all elements. func (s *parentStack) setParents(finfo *fieldInfo, vf reflect.Value) error { xmlns := s.p.defaultNS if finfo.xmlns != "" { xmlns = finfo.xmlns } commonParents := 0 if xmlns == s.xmlns { for ; commonParents < len(finfo.parents) && commonParents < len(s.parents); commonParents++ { if finfo.parents[commonParents] != s.parents[commonParents] { break } } } // Pop off any parents that aren't in common with the previous field. for i := len(s.parents) - 1; i >= commonParents; i-- { if err := s.p.writeEnd(Name{ Space: s.xmlns, Local: s.parents[i], }); err != nil { return err } } s.parents = finfo.parents s.xmlns = xmlns if commonParents >= len(s.parents) { // No new elements to push. return nil } if (vf.Kind() == reflect.Ptr || vf.Kind() == reflect.Interface) && vf.IsNil() { // The element is nil, so no need for the start elements. s.parents = s.parents[:commonParents] return nil } // Push any new parents required. for _, name := range s.parents[commonParents:] { start := &StartElement{ Name: Name{ Space: s.xmlns, Local: name, }, } // Set the default name space for parent elements // to match what we do with other elements. if s.xmlns != s.p.defaultNS { start.setDefaultNamespace() } if err := s.p.writeStart(start); err != nil { return err } } return nil } // A MarshalXMLError is returned when Marshal encounters a type // that cannot be converted into XML. type UnsupportedTypeError struct { Type reflect.Type } func (e *UnsupportedTypeError) Error() string { return "xml: unsupported type: " + e.Type.String() } func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0 case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Interface, reflect.Ptr: return v.IsNil() } return false } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/xml/marshal_test.go000066400000000000000000001374341264464372400273550ustar00rootroot00000000000000// 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 xml import ( "bytes" "errors" "fmt" "io" "reflect" "strconv" "strings" "sync" "testing" "time" ) type DriveType int const ( HyperDrive DriveType = iota ImprobabilityDrive ) type Passenger struct { Name []string `xml:"name"` Weight float32 `xml:"weight"` } type Ship struct { XMLName struct{} `xml:"spaceship"` Name string `xml:"name,attr"` Pilot string `xml:"pilot,attr"` Drive DriveType `xml:"drive"` Age uint `xml:"age"` Passenger []*Passenger `xml:"passenger"` secret string } type NamedType string type Port struct { XMLName struct{} `xml:"port"` Type string `xml:"type,attr,omitempty"` Comment string `xml:",comment"` Number string `xml:",chardata"` } type Domain struct { XMLName struct{} `xml:"domain"` Country string `xml:",attr,omitempty"` Name []byte `xml:",chardata"` Comment []byte `xml:",comment"` } type Book struct { XMLName struct{} `xml:"book"` Title string `xml:",chardata"` } type Event struct { XMLName struct{} `xml:"event"` Year int `xml:",chardata"` } type Movie struct { XMLName struct{} `xml:"movie"` Length uint `xml:",chardata"` } type Pi struct { XMLName struct{} `xml:"pi"` Approximation float32 `xml:",chardata"` } type Universe struct { XMLName struct{} `xml:"universe"` Visible float64 `xml:",chardata"` } type Particle struct { XMLName struct{} `xml:"particle"` HasMass bool `xml:",chardata"` } type Departure struct { XMLName struct{} `xml:"departure"` When time.Time `xml:",chardata"` } type SecretAgent struct { XMLName struct{} `xml:"agent"` Handle string `xml:"handle,attr"` Identity string Obfuscate string `xml:",innerxml"` } type NestedItems struct { XMLName struct{} `xml:"result"` Items []string `xml:">item"` Item1 []string `xml:"Items>item1"` } type NestedOrder struct { XMLName struct{} `xml:"result"` Field1 string `xml:"parent>c"` Field2 string `xml:"parent>b"` Field3 string `xml:"parent>a"` } type MixedNested struct { XMLName struct{} `xml:"result"` A string `xml:"parent1>a"` B string `xml:"b"` C string `xml:"parent1>parent2>c"` D string `xml:"parent1>d"` } type NilTest struct { A interface{} `xml:"parent1>parent2>a"` B interface{} `xml:"parent1>b"` C interface{} `xml:"parent1>parent2>c"` } type Service struct { XMLName struct{} `xml:"service"` Domain *Domain `xml:"host>domain"` Port *Port `xml:"host>port"` Extra1 interface{} Extra2 interface{} `xml:"host>extra2"` } var nilStruct *Ship type EmbedA struct { EmbedC EmbedB EmbedB FieldA string } type EmbedB struct { FieldB string *EmbedC } type EmbedC struct { FieldA1 string `xml:"FieldA>A1"` FieldA2 string `xml:"FieldA>A2"` FieldB string FieldC string } type NameCasing struct { XMLName struct{} `xml:"casing"` Xy string XY string XyA string `xml:"Xy,attr"` XYA string `xml:"XY,attr"` } type NamePrecedence struct { XMLName Name `xml:"Parent"` FromTag XMLNameWithoutTag `xml:"InTag"` FromNameVal XMLNameWithoutTag FromNameTag XMLNameWithTag InFieldName string } type XMLNameWithTag struct { XMLName Name `xml:"InXMLNameTag"` Value string `xml:",chardata"` } type XMLNameWithNSTag struct { XMLName Name `xml:"ns InXMLNameWithNSTag"` Value string `xml:",chardata"` } type XMLNameWithoutTag struct { XMLName Name Value string `xml:",chardata"` } type NameInField struct { Foo Name `xml:"ns foo"` } type AttrTest struct { Int int `xml:",attr"` Named int `xml:"int,attr"` Float float64 `xml:",attr"` Uint8 uint8 `xml:",attr"` Bool bool `xml:",attr"` Str string `xml:",attr"` Bytes []byte `xml:",attr"` } type OmitAttrTest struct { Int int `xml:",attr,omitempty"` Named int `xml:"int,attr,omitempty"` Float float64 `xml:",attr,omitempty"` Uint8 uint8 `xml:",attr,omitempty"` Bool bool `xml:",attr,omitempty"` Str string `xml:",attr,omitempty"` Bytes []byte `xml:",attr,omitempty"` } type OmitFieldTest struct { Int int `xml:",omitempty"` Named int `xml:"int,omitempty"` Float float64 `xml:",omitempty"` Uint8 uint8 `xml:",omitempty"` Bool bool `xml:",omitempty"` Str string `xml:",omitempty"` Bytes []byte `xml:",omitempty"` Ptr *PresenceTest `xml:",omitempty"` } type AnyTest struct { XMLName struct{} `xml:"a"` Nested string `xml:"nested>value"` AnyField AnyHolder `xml:",any"` } type AnyOmitTest struct { XMLName struct{} `xml:"a"` Nested string `xml:"nested>value"` AnyField *AnyHolder `xml:",any,omitempty"` } type AnySliceTest struct { XMLName struct{} `xml:"a"` Nested string `xml:"nested>value"` AnyField []AnyHolder `xml:",any"` } type AnyHolder struct { XMLName Name XML string `xml:",innerxml"` } type RecurseA struct { A string B *RecurseB } type RecurseB struct { A *RecurseA B string } type PresenceTest struct { Exists *struct{} } type IgnoreTest struct { PublicSecret string `xml:"-"` } type MyBytes []byte type Data struct { Bytes []byte Attr []byte `xml:",attr"` Custom MyBytes } type Plain struct { V interface{} } type MyInt int type EmbedInt struct { MyInt } type Strings struct { X []string `xml:"A>B,omitempty"` } type PointerFieldsTest struct { XMLName Name `xml:"dummy"` Name *string `xml:"name,attr"` Age *uint `xml:"age,attr"` Empty *string `xml:"empty,attr"` Contents *string `xml:",chardata"` } type ChardataEmptyTest struct { XMLName Name `xml:"test"` Contents *string `xml:",chardata"` } type MyMarshalerTest struct { } var _ Marshaler = (*MyMarshalerTest)(nil) func (m *MyMarshalerTest) MarshalXML(e *Encoder, start StartElement) error { e.EncodeToken(start) e.EncodeToken(CharData([]byte("hello world"))) e.EncodeToken(EndElement{start.Name}) return nil } type MyMarshalerAttrTest struct{} var _ MarshalerAttr = (*MyMarshalerAttrTest)(nil) func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) { return Attr{name, "hello world"}, nil } type MyMarshalerValueAttrTest struct{} var _ MarshalerAttr = MyMarshalerValueAttrTest{} func (m MyMarshalerValueAttrTest) MarshalXMLAttr(name Name) (Attr, error) { return Attr{name, "hello world"}, nil } type MarshalerStruct struct { Foo MyMarshalerAttrTest `xml:",attr"` } type MarshalerValueStruct struct { Foo MyMarshalerValueAttrTest `xml:",attr"` } type InnerStruct struct { XMLName Name `xml:"testns outer"` } type OuterStruct struct { InnerStruct IntAttr int `xml:"int,attr"` } type OuterNamedStruct struct { InnerStruct XMLName Name `xml:"outerns test"` IntAttr int `xml:"int,attr"` } type OuterNamedOrderedStruct struct { XMLName Name `xml:"outerns test"` InnerStruct IntAttr int `xml:"int,attr"` } type OuterOuterStruct struct { OuterStruct } type NestedAndChardata struct { AB []string `xml:"A>B"` Chardata string `xml:",chardata"` } type NestedAndComment struct { AB []string `xml:"A>B"` Comment string `xml:",comment"` } type XMLNSFieldStruct struct { Ns string `xml:"xmlns,attr"` Body string } type NamedXMLNSFieldStruct struct { XMLName struct{} `xml:"testns test"` Ns string `xml:"xmlns,attr"` Body string } type XMLNSFieldStructWithOmitEmpty struct { Ns string `xml:"xmlns,attr,omitempty"` Body string } type NamedXMLNSFieldStructWithEmptyNamespace struct { XMLName struct{} `xml:"test"` Ns string `xml:"xmlns,attr"` Body string } type RecursiveXMLNSFieldStruct struct { Ns string `xml:"xmlns,attr"` Body *RecursiveXMLNSFieldStruct `xml:",omitempty"` Text string `xml:",omitempty"` } func ifaceptr(x interface{}) interface{} { return &x } var ( nameAttr = "Sarah" ageAttr = uint(12) contentsAttr = "lorem ipsum" ) // Unless explicitly stated as such (or *Plain), all of the // tests below are two-way tests. When introducing new tests, // please try to make them two-way as well to ensure that // marshalling and unmarshalling are as symmetrical as feasible. var marshalTests = []struct { Value interface{} ExpectXML string MarshalOnly bool UnmarshalOnly bool }{ // Test nil marshals to nothing {Value: nil, ExpectXML: ``, MarshalOnly: true}, {Value: nilStruct, ExpectXML: ``, MarshalOnly: true}, // Test value types {Value: &Plain{true}, ExpectXML: `true`}, {Value: &Plain{false}, ExpectXML: `false`}, {Value: &Plain{int(42)}, ExpectXML: `42`}, {Value: &Plain{int8(42)}, ExpectXML: `42`}, {Value: &Plain{int16(42)}, ExpectXML: `42`}, {Value: &Plain{int32(42)}, ExpectXML: `42`}, {Value: &Plain{uint(42)}, ExpectXML: `42`}, {Value: &Plain{uint8(42)}, ExpectXML: `42`}, {Value: &Plain{uint16(42)}, ExpectXML: `42`}, {Value: &Plain{uint32(42)}, ExpectXML: `42`}, {Value: &Plain{float32(1.25)}, ExpectXML: `1.25`}, {Value: &Plain{float64(1.25)}, ExpectXML: `1.25`}, {Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `65501`}, {Value: &Plain{"gopher"}, ExpectXML: `gopher`}, {Value: &Plain{[]byte("gopher")}, ExpectXML: `gopher`}, {Value: &Plain{""}, ExpectXML: `</>`}, {Value: &Plain{[]byte("")}, ExpectXML: `</>`}, {Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `</>`}, {Value: &Plain{NamedType("potato")}, ExpectXML: `potato`}, {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `123`}, {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `123`}, {Value: ifaceptr(true), MarshalOnly: true, ExpectXML: `true`}, // Test time. { Value: &Plain{time.Unix(1e9, 123456789).UTC()}, ExpectXML: `2001-09-09T01:46:40.123456789Z`, }, // A pointer to struct{} may be used to test for an element's presence. { Value: &PresenceTest{new(struct{})}, ExpectXML: ``, }, { Value: &PresenceTest{}, ExpectXML: ``, }, // A pointer to struct{} may be used to test for an element's presence. { Value: &PresenceTest{new(struct{})}, ExpectXML: ``, }, { Value: &PresenceTest{}, ExpectXML: ``, }, // A []byte field is only nil if the element was not found. { Value: &Data{}, ExpectXML: ``, UnmarshalOnly: true, }, { Value: &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}}, ExpectXML: ``, UnmarshalOnly: true, }, // Check that []byte works, including named []byte types. { Value: &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}}, ExpectXML: `abcd`, }, // Test innerxml { Value: &SecretAgent{ Handle: "007", Identity: "James Bond", Obfuscate: "", }, ExpectXML: `James Bond`, MarshalOnly: true, }, { Value: &SecretAgent{ Handle: "007", Identity: "James Bond", Obfuscate: "James Bond", }, ExpectXML: `James Bond`, UnmarshalOnly: true, }, // Test structs {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `443`}, {Value: &Port{Number: "443"}, ExpectXML: `443`}, {Value: &Port{Type: ""}, ExpectXML: ``}, {Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `443`}, {Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `443`, MarshalOnly: true}, {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `google.com&friends`}, {Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `google.com`}, {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `Pride & Prejudice`}, {Value: &Event{Year: -3114}, ExpectXML: `-3114`}, {Value: &Movie{Length: 13440}, ExpectXML: `13440`}, {Value: &Pi{Approximation: 3.14159265}, ExpectXML: `3.1415927`}, {Value: &Universe{Visible: 9.3e13}, ExpectXML: `9.3e+13`}, {Value: &Particle{HasMass: true}, ExpectXML: `true`}, {Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `2013-01-09T00:15:00-09:00`}, {Value: atomValue, ExpectXML: atomXml}, { Value: &Ship{ Name: "Heart of Gold", Pilot: "Computer", Age: 1, Drive: ImprobabilityDrive, Passenger: []*Passenger{ { Name: []string{"Zaphod", "Beeblebrox"}, Weight: 7.25, }, { Name: []string{"Trisha", "McMillen"}, Weight: 5.5, }, { Name: []string{"Ford", "Prefect"}, Weight: 7, }, { Name: []string{"Arthur", "Dent"}, Weight: 6.75, }, }, }, ExpectXML: `` + `` + strconv.Itoa(int(ImprobabilityDrive)) + `` + `1` + `` + `Zaphod` + `Beeblebrox` + `7.25` + `` + `` + `Trisha` + `McMillen` + `5.5` + `` + `` + `Ford` + `Prefect` + `7` + `` + `` + `Arthur` + `Dent` + `6.75` + `` + ``, }, // Test a>b { Value: &NestedItems{Items: nil, Item1: nil}, ExpectXML: `` + `` + `` + ``, }, { Value: &NestedItems{Items: []string{}, Item1: []string{}}, ExpectXML: `` + `` + `` + ``, MarshalOnly: true, }, { Value: &NestedItems{Items: nil, Item1: []string{"A"}}, ExpectXML: `` + `` + `A` + `` + ``, }, { Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil}, ExpectXML: `` + `` + `A` + `B` + `` + ``, }, { Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}}, ExpectXML: `` + `` + `A` + `B` + `C` + `` + ``, }, { Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"}, ExpectXML: `` + `` + `C` + `B` + `A` + `` + ``, }, { Value: &NilTest{A: "A", B: nil, C: "C"}, ExpectXML: `` + `` + `A` + `C` + `` + ``, MarshalOnly: true, // Uses interface{} }, { Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"}, ExpectXML: `` + `A` + `B` + `` + `C` + `D` + `` + ``, }, { Value: &Service{Port: &Port{Number: "80"}}, ExpectXML: `80`, }, { Value: &Service{}, ExpectXML: ``, }, { Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"}, ExpectXML: `` + `80` + `A` + `B` + ``, MarshalOnly: true, }, { Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"}, ExpectXML: `` + `80` + `example` + ``, MarshalOnly: true, }, { Value: &struct { XMLName struct{} `xml:"space top"` A string `xml:"x>a"` B string `xml:"x>b"` C string `xml:"space x>c"` C1 string `xml:"space1 x>c"` D1 string `xml:"space1 x>d"` E1 string `xml:"x>e"` }{ A: "a", B: "b", C: "c", C1: "c1", D1: "d1", E1: "e1", }, ExpectXML: `` + `abc` + `` + `c1` + `d1` + `` + `` + `e1` + `` + ``, }, { Value: &struct { XMLName Name A string `xml:"x>a"` B string `xml:"x>b"` C string `xml:"space x>c"` C1 string `xml:"space1 x>c"` D1 string `xml:"space1 x>d"` }{ XMLName: Name{ Space: "space0", Local: "top", }, A: "a", B: "b", C: "c", C1: "c1", D1: "d1", }, ExpectXML: `` + `ab` + `c` + `` + `c1` + `d1` + `` + ``, }, { Value: &struct { XMLName struct{} `xml:"top"` B string `xml:"space x>b"` B1 string `xml:"space1 x>b"` }{ B: "b", B1: "b1", }, ExpectXML: `` + `b` + `b1` + ``, }, // Test struct embedding { Value: &EmbedA{ EmbedC: EmbedC{ FieldA1: "", // Shadowed by A.A FieldA2: "", // Shadowed by A.A FieldB: "A.C.B", FieldC: "A.C.C", }, EmbedB: EmbedB{ FieldB: "A.B.B", EmbedC: &EmbedC{ FieldA1: "A.B.C.A1", FieldA2: "A.B.C.A2", FieldB: "", // Shadowed by A.B.B FieldC: "A.B.C.C", }, }, FieldA: "A.A", }, ExpectXML: `` + `A.C.B` + `A.C.C` + `` + `A.B.B` + `` + `A.B.C.A1` + `A.B.C.A2` + `` + `A.B.C.C` + `` + `A.A` + ``, }, // Test that name casing matters { Value: &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"}, ExpectXML: `mixedupper`, }, // Test the order in which the XML element name is chosen { Value: &NamePrecedence{ FromTag: XMLNameWithoutTag{Value: "A"}, FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"}, FromNameTag: XMLNameWithTag{Value: "C"}, InFieldName: "D", }, ExpectXML: `` + `A` + `B` + `C` + `D` + ``, MarshalOnly: true, }, { Value: &NamePrecedence{ XMLName: Name{Local: "Parent"}, FromTag: XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"}, FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"}, FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"}, InFieldName: "D", }, ExpectXML: `` + `A` + `B` + `C` + `D` + ``, UnmarshalOnly: true, }, // xml.Name works in a plain field as well. { Value: &NameInField{Name{Space: "ns", Local: "foo"}}, ExpectXML: ``, }, { Value: &NameInField{Name{Space: "ns", Local: "foo"}}, ExpectXML: ``, UnmarshalOnly: true, }, // Marshaling zero xml.Name uses the tag or field name. { Value: &NameInField{}, ExpectXML: ``, MarshalOnly: true, }, // Test attributes { Value: &AttrTest{ Int: 8, Named: 9, Float: 23.5, Uint8: 255, Bool: true, Str: "str", Bytes: []byte("byt"), }, ExpectXML: ``, }, { Value: &AttrTest{Bytes: []byte{}}, ExpectXML: ``, }, { Value: &OmitAttrTest{ Int: 8, Named: 9, Float: 23.5, Uint8: 255, Bool: true, Str: "str", Bytes: []byte("byt"), }, ExpectXML: ``, }, { Value: &OmitAttrTest{}, ExpectXML: ``, }, // pointer fields { Value: &PointerFieldsTest{Name: &nameAttr, Age: &ageAttr, Contents: &contentsAttr}, ExpectXML: `lorem ipsum`, MarshalOnly: true, }, // empty chardata pointer field { Value: &ChardataEmptyTest{}, ExpectXML: ``, MarshalOnly: true, }, // omitempty on fields { Value: &OmitFieldTest{ Int: 8, Named: 9, Float: 23.5, Uint8: 255, Bool: true, Str: "str", Bytes: []byte("byt"), Ptr: &PresenceTest{}, }, ExpectXML: `` + `8` + `9` + `23.5` + `255` + `true` + `str` + `byt` + `` + ``, }, { Value: &OmitFieldTest{}, ExpectXML: ``, }, // Test ",any" { ExpectXML: `knownunknown`, Value: &AnyTest{ Nested: "known", AnyField: AnyHolder{ XMLName: Name{Local: "other"}, XML: "unknown", }, }, }, { Value: &AnyTest{Nested: "known", AnyField: AnyHolder{ XML: "", XMLName: Name{Local: "AnyField"}, }, }, ExpectXML: `known`, }, { ExpectXML: `b`, Value: &AnyOmitTest{ Nested: "b", }, }, { ExpectXML: `bei`, Value: &AnySliceTest{ Nested: "b", AnyField: []AnyHolder{ { XMLName: Name{Local: "c"}, XML: "e", }, { XMLName: Name{Space: "f", Local: "g"}, XML: "i", }, }, }, }, { ExpectXML: `b`, Value: &AnySliceTest{ Nested: "b", }, }, // Test recursive types. { Value: &RecurseA{ A: "a1", B: &RecurseB{ A: &RecurseA{"a2", nil}, B: "b1", }, }, ExpectXML: `a1a2b1`, }, // Test ignoring fields via "-" tag { ExpectXML: ``, Value: &IgnoreTest{}, }, { ExpectXML: ``, Value: &IgnoreTest{PublicSecret: "can't tell"}, MarshalOnly: true, }, { ExpectXML: `ignore me`, Value: &IgnoreTest{}, UnmarshalOnly: true, }, // Test escaping. { ExpectXML: `dquote: "; squote: '; ampersand: &; less: <; greater: >;`, Value: &AnyTest{ Nested: `dquote: "; squote: '; ampersand: &; less: <; greater: >;`, AnyField: AnyHolder{XMLName: Name{Local: "empty"}}, }, }, { ExpectXML: `newline: ; cr: ; tab: ;`, Value: &AnyTest{ Nested: "newline: \n; cr: \r; tab: \t;", AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}}, }, }, { ExpectXML: "1\r2\r\n3\n\r4\n5", Value: &AnyTest{ Nested: "1\n2\n3\n\n4\n5", }, UnmarshalOnly: true, }, { ExpectXML: `42`, Value: &EmbedInt{ MyInt: 42, }, }, // Test omitempty with parent chain; see golang.org/issue/4168. { ExpectXML: ``, Value: &Strings{}, }, // Custom marshalers. { ExpectXML: `hello world`, Value: &MyMarshalerTest{}, }, { ExpectXML: ``, Value: &MarshalerStruct{}, }, { ExpectXML: ``, Value: &MarshalerValueStruct{}, }, { ExpectXML: ``, Value: &OuterStruct{IntAttr: 10}, }, { ExpectXML: ``, Value: &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10}, }, { ExpectXML: ``, Value: &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10}, }, { ExpectXML: ``, Value: &OuterOuterStruct{OuterStruct{IntAttr: 10}}, }, { ExpectXML: `test`, Value: &NestedAndChardata{AB: make([]string, 2), Chardata: "test"}, }, { ExpectXML: ``, Value: &NestedAndComment{AB: make([]string, 2), Comment: "test"}, }, { ExpectXML: `hello world`, Value: &XMLNSFieldStruct{Ns: "http://example.com/ns", Body: "hello world"}, }, { ExpectXML: `hello world`, Value: &NamedXMLNSFieldStruct{Ns: "http://example.com/ns", Body: "hello world"}, }, { ExpectXML: `hello world`, Value: &NamedXMLNSFieldStruct{Ns: "", Body: "hello world"}, }, { ExpectXML: `hello world`, Value: &XMLNSFieldStructWithOmitEmpty{Body: "hello world"}, }, { // The xmlns attribute must be ignored because the // element is in the empty namespace, so it's not possible // to set the default namespace to something non-empty. ExpectXML: `hello world`, Value: &NamedXMLNSFieldStructWithEmptyNamespace{Ns: "foo", Body: "hello world"}, MarshalOnly: true, }, { ExpectXML: `hello world`, Value: &RecursiveXMLNSFieldStruct{ Ns: "foo", Body: &RecursiveXMLNSFieldStruct{ Text: "hello world", }, }, }, } func TestMarshal(t *testing.T) { for idx, test := range marshalTests { if test.UnmarshalOnly { continue } data, err := Marshal(test.Value) if err != nil { t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err) continue } if got, want := string(data), test.ExpectXML; got != want { if strings.Contains(want, "\n") { t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want) } else { t.Errorf("#%d: marshal(%#v):\nhave %#q\nwant %#q", idx, test.Value, got, want) } } } } type AttrParent struct { X string `xml:"X>Y,attr"` } type BadAttr struct { Name []string `xml:"name,attr"` } var marshalErrorTests = []struct { Value interface{} Err string Kind reflect.Kind }{ { Value: make(chan bool), Err: "xml: unsupported type: chan bool", Kind: reflect.Chan, }, { Value: map[string]string{ "question": "What do you get when you multiply six by nine?", "answer": "42", }, Err: "xml: unsupported type: map[string]string", Kind: reflect.Map, }, { Value: map[*Ship]bool{nil: false}, Err: "xml: unsupported type: map[*xml.Ship]bool", Kind: reflect.Map, }, { Value: &Domain{Comment: []byte("f--bar")}, Err: `xml: comments must not contain "--"`, }, // Reject parent chain with attr, never worked; see golang.org/issue/5033. { Value: &AttrParent{}, Err: `xml: X>Y chain not valid with attr flag`, }, { Value: BadAttr{[]string{"X", "Y"}}, Err: `xml: unsupported type: []string`, }, } var marshalIndentTests = []struct { Value interface{} Prefix string Indent string ExpectXML string }{ { Value: &SecretAgent{ Handle: "007", Identity: "James Bond", Obfuscate: "", }, Prefix: "", Indent: "\t", ExpectXML: fmt.Sprintf("\n\tJames Bond\n"), }, } func TestMarshalErrors(t *testing.T) { for idx, test := range marshalErrorTests { data, err := Marshal(test.Value) if err == nil { t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err) continue } if err.Error() != test.Err { t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err) } if test.Kind != reflect.Invalid { if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind { t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind) } } } } // Do invertibility testing on the various structures that we test func TestUnmarshal(t *testing.T) { for i, test := range marshalTests { if test.MarshalOnly { continue } if _, ok := test.Value.(*Plain); ok { continue } vt := reflect.TypeOf(test.Value) dest := reflect.New(vt.Elem()).Interface() err := Unmarshal([]byte(test.ExpectXML), dest) switch fix := dest.(type) { case *Feed: fix.Author.InnerXML = "" for i := range fix.Entry { fix.Entry[i].Author.InnerXML = "" } } if err != nil { t.Errorf("#%d: unexpected error: %#v", i, err) } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) { t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want) } } } func TestMarshalIndent(t *testing.T) { for i, test := range marshalIndentTests { data, err := MarshalIndent(test.Value, test.Prefix, test.Indent) if err != nil { t.Errorf("#%d: Error: %s", i, err) continue } if got, want := string(data), test.ExpectXML; got != want { t.Errorf("#%d: MarshalIndent:\nGot:%s\nWant:\n%s", i, got, want) } } } type limitedBytesWriter struct { w io.Writer remain int // until writes fail } func (lw *limitedBytesWriter) Write(p []byte) (n int, err error) { if lw.remain <= 0 { println("error") return 0, errors.New("write limit hit") } if len(p) > lw.remain { p = p[:lw.remain] n, _ = lw.w.Write(p) lw.remain = 0 return n, errors.New("write limit hit") } n, err = lw.w.Write(p) lw.remain -= n return n, err } func TestMarshalWriteErrors(t *testing.T) { var buf bytes.Buffer const writeCap = 1024 w := &limitedBytesWriter{&buf, writeCap} enc := NewEncoder(w) var err error var i int const n = 4000 for i = 1; i <= n; i++ { err = enc.Encode(&Passenger{ Name: []string{"Alice", "Bob"}, Weight: 5, }) if err != nil { break } } if err == nil { t.Error("expected an error") } if i == n { t.Errorf("expected to fail before the end") } if buf.Len() != writeCap { t.Errorf("buf.Len() = %d; want %d", buf.Len(), writeCap) } } func TestMarshalWriteIOErrors(t *testing.T) { enc := NewEncoder(errWriter{}) expectErr := "unwritable" err := enc.Encode(&Passenger{}) if err == nil || err.Error() != expectErr { t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr) } } func TestMarshalFlush(t *testing.T) { var buf bytes.Buffer enc := NewEncoder(&buf) if err := enc.EncodeToken(CharData("hello world")); err != nil { t.Fatalf("enc.EncodeToken: %v", err) } if buf.Len() > 0 { t.Fatalf("enc.EncodeToken caused actual write: %q", buf.Bytes()) } if err := enc.Flush(); err != nil { t.Fatalf("enc.Flush: %v", err) } if buf.String() != "hello world" { t.Fatalf("after enc.Flush, buf.String() = %q, want %q", buf.String(), "hello world") } } var encodeElementTests = []struct { desc string value interface{} start StartElement expectXML string }{{ desc: "simple string", value: "hello", start: StartElement{ Name: Name{Local: "a"}, }, expectXML: `hello`, }, { desc: "string with added attributes", value: "hello", start: StartElement{ Name: Name{Local: "a"}, Attr: []Attr{{ Name: Name{Local: "x"}, Value: "y", }, { Name: Name{Local: "foo"}, Value: "bar", }}, }, expectXML: `hello`, }, { desc: "start element with default name space", value: struct { Foo XMLNameWithNSTag }{ Foo: XMLNameWithNSTag{ Value: "hello", }, }, start: StartElement{ Name: Name{Space: "ns", Local: "a"}, Attr: []Attr{{ Name: Name{Local: "xmlns"}, // "ns" is the name space defined in XMLNameWithNSTag Value: "ns", }}, }, expectXML: `hello`, }, { desc: "start element in name space with different default name space", value: struct { Foo XMLNameWithNSTag }{ Foo: XMLNameWithNSTag{ Value: "hello", }, }, start: StartElement{ Name: Name{Space: "ns2", Local: "a"}, Attr: []Attr{{ Name: Name{Local: "xmlns"}, // "ns" is the name space defined in XMLNameWithNSTag Value: "ns", }}, }, expectXML: `hello`, }, { desc: "XMLMarshaler with start element with default name space", value: &MyMarshalerTest{}, start: StartElement{ Name: Name{Space: "ns2", Local: "a"}, Attr: []Attr{{ Name: Name{Local: "xmlns"}, // "ns" is the name space defined in XMLNameWithNSTag Value: "ns", }}, }, expectXML: `hello world`, }} func TestEncodeElement(t *testing.T) { for idx, test := range encodeElementTests { var buf bytes.Buffer enc := NewEncoder(&buf) err := enc.EncodeElement(test.value, test.start) if err != nil { t.Fatalf("enc.EncodeElement: %v", err) } err = enc.Flush() if err != nil { t.Fatalf("enc.Flush: %v", err) } if got, want := buf.String(), test.expectXML; got != want { t.Errorf("#%d(%s): EncodeElement(%#v, %#v):\nhave %#q\nwant %#q", idx, test.desc, test.value, test.start, got, want) } } } func BenchmarkMarshal(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { Marshal(atomValue) } } func BenchmarkUnmarshal(b *testing.B) { b.ReportAllocs() xml := []byte(atomXml) for i := 0; i < b.N; i++ { Unmarshal(xml, &Feed{}) } } // golang.org/issue/6556 func TestStructPointerMarshal(t *testing.T) { type A struct { XMLName string `xml:"a"` B []interface{} } type C struct { XMLName Name Value string `xml:"value"` } a := new(A) a.B = append(a.B, &C{ XMLName: Name{Local: "c"}, Value: "x", }) b, err := Marshal(a) if err != nil { t.Fatal(err) } if x := string(b); x != "x" { t.Fatal(x) } var v A err = Unmarshal(b, &v) if err != nil { t.Fatal(err) } } var encodeTokenTests = []struct { desc string toks []Token want string err string }{{ desc: "start element with name space", toks: []Token{ StartElement{Name{"space", "local"}, nil}, }, want: ``, }, { desc: "start element with no name", toks: []Token{ StartElement{Name{"space", ""}, nil}, }, err: "xml: start tag with no name", }, { desc: "end element with no name", toks: []Token{ EndElement{Name{"space", ""}}, }, err: "xml: end tag with no name", }, { desc: "char data", toks: []Token{ CharData("foo"), }, want: `foo`, }, { desc: "char data with escaped chars", toks: []Token{ CharData(" \t\n"), }, want: " \n", }, { desc: "comment", toks: []Token{ Comment("foo"), }, want: ``, }, { desc: "comment with invalid content", toks: []Token{ Comment("foo-->"), }, err: "xml: EncodeToken of Comment containing --> marker", }, { desc: "proc instruction", toks: []Token{ ProcInst{"Target", []byte("Instruction")}, }, want: ``, }, { desc: "proc instruction with empty target", toks: []Token{ ProcInst{"", []byte("Instruction")}, }, err: "xml: EncodeToken of ProcInst with invalid Target", }, { desc: "proc instruction with bad content", toks: []Token{ ProcInst{"", []byte("Instruction?>")}, }, err: "xml: EncodeToken of ProcInst with invalid Target", }, { desc: "directive", toks: []Token{ Directive("foo"), }, want: ``, }, { desc: "more complex directive", toks: []Token{ Directive("DOCTYPE doc [ '> ]"), }, want: `'> ]>`, }, { desc: "directive instruction with bad name", toks: []Token{ Directive("foo>"), }, err: "xml: EncodeToken of Directive containing wrong < or > markers", }, { desc: "end tag without start tag", toks: []Token{ EndElement{Name{"foo", "bar"}}, }, err: "xml: end tag without start tag", }, { desc: "mismatching end tag local name", toks: []Token{ StartElement{Name{"", "foo"}, nil}, EndElement{Name{"", "bar"}}, }, err: "xml: end tag does not match start tag ", want: ``, }, { desc: "mismatching end tag namespace", toks: []Token{ StartElement{Name{"space", "foo"}, nil}, EndElement{Name{"another", "foo"}}, }, err: "xml: end tag in namespace another does not match start tag in namespace space", want: ``, }, { desc: "start element with explicit namespace", toks: []Token{ StartElement{Name{"space", "local"}, []Attr{ {Name{"xmlns", "x"}, "space"}, {Name{"space", "foo"}, "value"}, }}, }, want: ``, }, { desc: "start element with explicit namespace and colliding prefix", toks: []Token{ StartElement{Name{"space", "local"}, []Attr{ {Name{"xmlns", "x"}, "space"}, {Name{"space", "foo"}, "value"}, {Name{"x", "bar"}, "other"}, }}, }, want: ``, }, { desc: "start element using previously defined namespace", toks: []Token{ StartElement{Name{"", "local"}, []Attr{ {Name{"xmlns", "x"}, "space"}, }}, StartElement{Name{"space", "foo"}, []Attr{ {Name{"space", "x"}, "y"}, }}, }, want: ``, }, { desc: "nested name space with same prefix", toks: []Token{ StartElement{Name{"", "foo"}, []Attr{ {Name{"xmlns", "x"}, "space1"}, }}, StartElement{Name{"", "foo"}, []Attr{ {Name{"xmlns", "x"}, "space2"}, }}, StartElement{Name{"", "foo"}, []Attr{ {Name{"space1", "a"}, "space1 value"}, {Name{"space2", "b"}, "space2 value"}, }}, EndElement{Name{"", "foo"}}, EndElement{Name{"", "foo"}}, StartElement{Name{"", "foo"}, []Attr{ {Name{"space1", "a"}, "space1 value"}, {Name{"space2", "b"}, "space2 value"}, }}, }, want: ``, }, { desc: "start element defining several prefixes for the same name space", toks: []Token{ StartElement{Name{"space", "foo"}, []Attr{ {Name{"xmlns", "a"}, "space"}, {Name{"xmlns", "b"}, "space"}, {Name{"space", "x"}, "value"}, }}, }, want: ``, }, { desc: "nested element redefines name space", toks: []Token{ StartElement{Name{"", "foo"}, []Attr{ {Name{"xmlns", "x"}, "space"}, }}, StartElement{Name{"space", "foo"}, []Attr{ {Name{"xmlns", "y"}, "space"}, {Name{"space", "a"}, "value"}, }}, }, want: ``, }, { desc: "nested element creates alias for default name space", toks: []Token{ StartElement{Name{"space", "foo"}, []Attr{ {Name{"", "xmlns"}, "space"}, }}, StartElement{Name{"space", "foo"}, []Attr{ {Name{"xmlns", "y"}, "space"}, {Name{"space", "a"}, "value"}, }}, }, want: ``, }, { desc: "nested element defines default name space with existing prefix", toks: []Token{ StartElement{Name{"", "foo"}, []Attr{ {Name{"xmlns", "x"}, "space"}, }}, StartElement{Name{"space", "foo"}, []Attr{ {Name{"", "xmlns"}, "space"}, {Name{"space", "a"}, "value"}, }}, }, want: ``, }, { desc: "nested element uses empty attribute name space when default ns defined", toks: []Token{ StartElement{Name{"space", "foo"}, []Attr{ {Name{"", "xmlns"}, "space"}, }}, StartElement{Name{"space", "foo"}, []Attr{ {Name{"", "attr"}, "value"}, }}, }, want: ``, }, { desc: "redefine xmlns", toks: []Token{ StartElement{Name{"", "foo"}, []Attr{ {Name{"foo", "xmlns"}, "space"}, }}, }, err: `xml: cannot redefine xmlns attribute prefix`, }, { desc: "xmlns with explicit name space #1", toks: []Token{ StartElement{Name{"space", "foo"}, []Attr{ {Name{"xml", "xmlns"}, "space"}, }}, }, want: ``, }, { desc: "xmlns with explicit name space #2", toks: []Token{ StartElement{Name{"space", "foo"}, []Attr{ {Name{xmlURL, "xmlns"}, "space"}, }}, }, want: ``, }, { desc: "empty name space declaration is ignored", toks: []Token{ StartElement{Name{"", "foo"}, []Attr{ {Name{"xmlns", "foo"}, ""}, }}, }, want: ``, }, { desc: "attribute with no name is ignored", toks: []Token{ StartElement{Name{"", "foo"}, []Attr{ {Name{"", ""}, "value"}, }}, }, want: ``, }, { desc: "namespace URL with non-valid name", toks: []Token{ StartElement{Name{"/34", "foo"}, []Attr{ {Name{"/34", "x"}, "value"}, }}, }, want: `<_:foo xmlns:_="/34" _:x="value">`, }, { desc: "nested element resets default namespace to empty", toks: []Token{ StartElement{Name{"space", "foo"}, []Attr{ {Name{"", "xmlns"}, "space"}, }}, StartElement{Name{"", "foo"}, []Attr{ {Name{"", "xmlns"}, ""}, {Name{"", "x"}, "value"}, {Name{"space", "x"}, "value"}, }}, }, want: ``, }, { desc: "nested element requires empty default name space", toks: []Token{ StartElement{Name{"space", "foo"}, []Attr{ {Name{"", "xmlns"}, "space"}, }}, StartElement{Name{"", "foo"}, nil}, }, want: ``, }, { desc: "attribute uses name space from xmlns", toks: []Token{ StartElement{Name{"some/space", "foo"}, []Attr{ {Name{"", "attr"}, "value"}, {Name{"some/space", "other"}, "other value"}, }}, }, want: ``, }, { desc: "default name space should not be used by attributes", toks: []Token{ StartElement{Name{"space", "foo"}, []Attr{ {Name{"", "xmlns"}, "space"}, {Name{"xmlns", "bar"}, "space"}, {Name{"space", "baz"}, "foo"}, }}, StartElement{Name{"space", "baz"}, nil}, EndElement{Name{"space", "baz"}}, EndElement{Name{"space", "foo"}}, }, want: ``, }, { desc: "default name space not used by attributes, not explicitly defined", toks: []Token{ StartElement{Name{"space", "foo"}, []Attr{ {Name{"", "xmlns"}, "space"}, {Name{"space", "baz"}, "foo"}, }}, StartElement{Name{"space", "baz"}, nil}, EndElement{Name{"space", "baz"}}, EndElement{Name{"space", "foo"}}, }, want: ``, }, { desc: "impossible xmlns declaration", toks: []Token{ StartElement{Name{"", "foo"}, []Attr{ {Name{"", "xmlns"}, "space"}, }}, StartElement{Name{"space", "bar"}, []Attr{ {Name{"space", "attr"}, "value"}, }}, }, want: ``, }} func TestEncodeToken(t *testing.T) { loop: for i, tt := range encodeTokenTests { var buf bytes.Buffer enc := NewEncoder(&buf) var err error for j, tok := range tt.toks { err = enc.EncodeToken(tok) if err != nil && j < len(tt.toks)-1 { t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err) continue loop } } errorf := func(f string, a ...interface{}) { t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...)) } switch { case tt.err != "" && err == nil: errorf(" expected error; got none") continue case tt.err == "" && err != nil: errorf(" got error: %v", err) continue case tt.err != "" && err != nil && tt.err != err.Error(): errorf(" error mismatch; got %v, want %v", err, tt.err) continue } if err := enc.Flush(); err != nil { errorf(" %v", err) continue } if got := buf.String(); got != tt.want { errorf("\ngot %v\nwant %v", got, tt.want) continue } } } func TestProcInstEncodeToken(t *testing.T) { var buf bytes.Buffer enc := NewEncoder(&buf) if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil { t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err) } if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil { t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst") } if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil { t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token") } } func TestDecodeEncode(t *testing.T) { var in, out bytes.Buffer in.WriteString(` `) dec := NewDecoder(&in) enc := NewEncoder(&out) for tok, err := dec.Token(); err == nil; tok, err = dec.Token() { err = enc.EncodeToken(tok) if err != nil { t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err) } } } // Issue 9796. Used to fail with GORACE="halt_on_error=1" -race. func TestRace9796(t *testing.T) { type A struct{} type B struct { C []A `xml:"X>Y"` } var wg sync.WaitGroup for i := 0; i < 2; i++ { wg.Add(1) go func() { Marshal(B{[]A{A{}}}) wg.Done() }() } wg.Wait() } func TestIsValidDirective(t *testing.T) { testOK := []string{ "<>", "< < > >", "' '>' >", " ]>", " '<' ' doc ANY> ]>", ">>> a < comment --> [ ] >", } testKO := []string{ "<", ">", "", "< > > < < >", " -->", "", "'", "", } for _, s := range testOK { if !isValidDirective(Directive(s)) { t.Errorf("Directive %q is expected to be valid", s) } } for _, s := range testKO { if isValidDirective(Directive(s)) { t.Errorf("Directive %q is expected to be invalid", s) } } } // Issue 11719. EncodeToken used to silently eat tokens with an invalid type. func TestSimpleUseOfEncodeToken(t *testing.T) { var buf bytes.Buffer enc := NewEncoder(&buf) if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil { t.Errorf("enc.EncodeToken: pointer type should be rejected") } if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil { t.Errorf("enc.EncodeToken: pointer type should be rejected") } if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil { t.Errorf("enc.EncodeToken: StartElement %s", err) } if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil { t.Errorf("enc.EncodeToken: EndElement %s", err) } if err := enc.EncodeToken(Universe{}); err == nil { t.Errorf("enc.EncodeToken: invalid type not caught") } if err := enc.Flush(); err != nil { t.Errorf("enc.Flush: %s", err) } if buf.Len() == 0 { t.Errorf("enc.EncodeToken: empty buffer") } want := "" if buf.String() != want { t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String()) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/xml/read.go000066400000000000000000000474651264464372400256060ustar00rootroot00000000000000// 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 xml import ( "bytes" "encoding" "errors" "fmt" "reflect" "strconv" "strings" ) // BUG(rsc): Mapping between XML elements and data structures is inherently flawed: // an XML element is an order-dependent collection of anonymous // values, while a data structure is an order-independent collection // of named values. // See package json for a textual representation more suitable // to data structures. // Unmarshal parses the XML-encoded data and stores the result in // the value pointed to by v, which must be an arbitrary struct, // slice, or string. Well-formed data that does not fit into v is // discarded. // // Because Unmarshal uses the reflect package, it can only assign // to exported (upper case) fields. Unmarshal uses a case-sensitive // comparison to match XML element names to tag values and struct // field names. // // Unmarshal maps an XML element to a struct using the following rules. // In the rules, the tag of a field refers to the value associated with the // key 'xml' in the struct field's tag (see the example above). // // * If the struct has a field of type []byte or string with tag // ",innerxml", Unmarshal accumulates the raw XML nested inside the // element in that field. The rest of the rules still apply. // // * If the struct has a field named XMLName of type xml.Name, // Unmarshal records the element name in that field. // // * If the XMLName field has an associated tag of the form // "name" or "namespace-URL name", the XML element must have // the given name (and, optionally, name space) or else Unmarshal // returns an error. // // * If the XML element has an attribute whose name matches a // struct field name with an associated tag containing ",attr" or // the explicit name in a struct field tag of the form "name,attr", // Unmarshal records the attribute value in that field. // // * If the XML element contains character data, that data is // accumulated in the first struct field that has tag ",chardata". // The struct field may have type []byte or string. // If there is no such field, the character data is discarded. // // * If the XML element contains comments, they are accumulated in // the first struct field that has tag ",comment". The struct // field may have type []byte or string. If there is no such // field, the comments are discarded. // // * If the XML element contains a sub-element whose name matches // the prefix of a tag formatted as "a" or "a>b>c", unmarshal // will descend into the XML structure looking for elements with the // given names, and will map the innermost elements to that struct // field. A tag starting with ">" is equivalent to one starting // with the field name followed by ">". // // * If the XML element contains a sub-element whose name matches // a struct field's XMLName tag and the struct field has no // explicit name tag as per the previous rule, unmarshal maps // the sub-element to that struct field. // // * If the XML element contains a sub-element whose name matches a // field without any mode flags (",attr", ",chardata", etc), Unmarshal // maps the sub-element to that struct field. // // * If the XML element contains a sub-element that hasn't matched any // of the above rules and the struct has a field with tag ",any", // unmarshal maps the sub-element to that struct field. // // * An anonymous struct field is handled as if the fields of its // value were part of the outer struct. // // * A struct field with tag "-" is never unmarshalled into. // // Unmarshal maps an XML element to a string or []byte by saving the // concatenation of that element's character data in the string or // []byte. The saved []byte is never nil. // // Unmarshal maps an attribute value to a string or []byte by saving // the value in the string or slice. // // Unmarshal maps an XML element to a slice by extending the length of // the slice and mapping the element to the newly created value. // // Unmarshal maps an XML element or attribute value to a bool by // setting it to the boolean value represented by the string. // // Unmarshal maps an XML element or attribute value to an integer or // floating-point field by setting the field to the result of // interpreting the string value in decimal. There is no check for // overflow. // // Unmarshal maps an XML element to an xml.Name by recording the // element name. // // Unmarshal maps an XML element to a pointer by setting the pointer // to a freshly allocated value and then mapping the element to that value. // func Unmarshal(data []byte, v interface{}) error { return NewDecoder(bytes.NewReader(data)).Decode(v) } // Decode works like xml.Unmarshal, except it reads the decoder // stream to find the start element. func (d *Decoder) Decode(v interface{}) error { return d.DecodeElement(v, nil) } // DecodeElement works like xml.Unmarshal except that it takes // a pointer to the start XML element to decode into v. // It is useful when a client reads some raw XML tokens itself // but also wants to defer to Unmarshal for some elements. func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error { val := reflect.ValueOf(v) if val.Kind() != reflect.Ptr { return errors.New("non-pointer passed to Unmarshal") } return d.unmarshal(val.Elem(), start) } // An UnmarshalError represents an error in the unmarshalling process. type UnmarshalError string func (e UnmarshalError) Error() string { return string(e) } // Unmarshaler is the interface implemented by objects that can unmarshal // an XML element description of themselves. // // UnmarshalXML decodes a single XML element // beginning with the given start element. // If it returns an error, the outer call to Unmarshal stops and // returns that error. // UnmarshalXML must consume exactly one XML element. // One common implementation strategy is to unmarshal into // a separate value with a layout matching the expected XML // using d.DecodeElement, and then to copy the data from // that value into the receiver. // Another common strategy is to use d.Token to process the // XML object one token at a time. // UnmarshalXML may not use d.RawToken. type Unmarshaler interface { UnmarshalXML(d *Decoder, start StartElement) error } // UnmarshalerAttr is the interface implemented by objects that can unmarshal // an XML attribute description of themselves. // // UnmarshalXMLAttr decodes a single XML attribute. // If it returns an error, the outer call to Unmarshal stops and // returns that error. // UnmarshalXMLAttr is used only for struct fields with the // "attr" option in the field tag. type UnmarshalerAttr interface { UnmarshalXMLAttr(attr Attr) error } // receiverType returns the receiver type to use in an expression like "%s.MethodName". func receiverType(val interface{}) string { t := reflect.TypeOf(val) if t.Name() != "" { return t.String() } return "(" + t.String() + ")" } // unmarshalInterface unmarshals a single XML element into val. // start is the opening tag of the element. func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error { // Record that decoder must stop at end tag corresponding to start. p.pushEOF() p.unmarshalDepth++ err := val.UnmarshalXML(p, *start) p.unmarshalDepth-- if err != nil { p.popEOF() return err } if !p.popEOF() { return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire <%s> element", receiverType(val), start.Name.Local) } return nil } // unmarshalTextInterface unmarshals a single XML element into val. // The chardata contained in the element (but not its children) // is passed to the text unmarshaler. func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler, start *StartElement) error { var buf []byte depth := 1 for depth > 0 { t, err := p.Token() if err != nil { return err } switch t := t.(type) { case CharData: if depth == 1 { buf = append(buf, t...) } case StartElement: depth++ case EndElement: depth-- } } return val.UnmarshalText(buf) } // unmarshalAttr unmarshals a single XML attribute into val. func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error { if val.Kind() == reflect.Ptr { if val.IsNil() { val.Set(reflect.New(val.Type().Elem())) } val = val.Elem() } if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) { // This is an unmarshaler with a non-pointer receiver, // so it's likely to be incorrect, but we do what we're told. return val.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(unmarshalerAttrType) { return pv.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr) } } // Not an UnmarshalerAttr; try encoding.TextUnmarshaler. if val.CanInterface() && val.Type().Implements(textUnmarshalerType) { // This is an unmarshaler with a non-pointer receiver, // so it's likely to be incorrect, but we do what we're told. return val.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value)) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) { return pv.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value)) } } copyValue(val, []byte(attr.Value)) return nil } var ( unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() unmarshalerAttrType = reflect.TypeOf((*UnmarshalerAttr)(nil)).Elem() textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() ) // Unmarshal a single XML element into val. func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { // Find start element if we need it. if start == nil { for { tok, err := p.Token() if err != nil { return err } if t, ok := tok.(StartElement); ok { start = &t break } } } // Load value from interface, but only if the result will be // usefully addressable. if val.Kind() == reflect.Interface && !val.IsNil() { e := val.Elem() if e.Kind() == reflect.Ptr && !e.IsNil() { val = e } } if val.Kind() == reflect.Ptr { if val.IsNil() { val.Set(reflect.New(val.Type().Elem())) } val = val.Elem() } if val.CanInterface() && val.Type().Implements(unmarshalerType) { // This is an unmarshaler with a non-pointer receiver, // so it's likely to be incorrect, but we do what we're told. return p.unmarshalInterface(val.Interface().(Unmarshaler), start) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(unmarshalerType) { return p.unmarshalInterface(pv.Interface().(Unmarshaler), start) } } if val.CanInterface() && val.Type().Implements(textUnmarshalerType) { return p.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler), start) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) { return p.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler), start) } } var ( data []byte saveData reflect.Value comment []byte saveComment reflect.Value saveXML reflect.Value saveXMLIndex int saveXMLData []byte saveAny reflect.Value sv reflect.Value tinfo *typeInfo err error ) switch v := val; v.Kind() { default: return errors.New("unknown type " + v.Type().String()) case reflect.Interface: // TODO: For now, simply ignore the field. In the near // future we may choose to unmarshal the start // element on it, if not nil. return p.Skip() case reflect.Slice: typ := v.Type() if typ.Elem().Kind() == reflect.Uint8 { // []byte saveData = v break } // Slice of element values. // Grow slice. n := v.Len() if n >= v.Cap() { ncap := 2 * n if ncap < 4 { ncap = 4 } new := reflect.MakeSlice(typ, n, ncap) reflect.Copy(new, v) v.Set(new) } v.SetLen(n + 1) // Recur to read element into slice. if err := p.unmarshal(v.Index(n), start); err != nil { v.SetLen(n) return err } return nil case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String: saveData = v case reflect.Struct: typ := v.Type() if typ == nameType { v.Set(reflect.ValueOf(start.Name)) break } sv = v tinfo, err = getTypeInfo(typ) if err != nil { return err } // Validate and assign element name. if tinfo.xmlname != nil { finfo := tinfo.xmlname if finfo.name != "" && finfo.name != start.Name.Local { return UnmarshalError("expected element type <" + finfo.name + "> but have <" + start.Name.Local + ">") } if finfo.xmlns != "" && finfo.xmlns != start.Name.Space { e := "expected element <" + finfo.name + "> in name space " + finfo.xmlns + " but have " if start.Name.Space == "" { e += "no name space" } else { e += start.Name.Space } return UnmarshalError(e) } fv := finfo.value(sv) if _, ok := fv.Interface().(Name); ok { fv.Set(reflect.ValueOf(start.Name)) } } // Assign attributes. // Also, determine whether we need to save character data or comments. for i := range tinfo.fields { finfo := &tinfo.fields[i] switch finfo.flags & fMode { case fAttr: strv := finfo.value(sv) // Look for attribute. for _, a := range start.Attr { if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) { if err := p.unmarshalAttr(strv, a); err != nil { return err } break } } case fCharData: if !saveData.IsValid() { saveData = finfo.value(sv) } case fComment: if !saveComment.IsValid() { saveComment = finfo.value(sv) } case fAny, fAny | fElement: if !saveAny.IsValid() { saveAny = finfo.value(sv) } case fInnerXml: if !saveXML.IsValid() { saveXML = finfo.value(sv) if p.saved == nil { saveXMLIndex = 0 p.saved = new(bytes.Buffer) } else { saveXMLIndex = p.savedOffset() } } } } } // Find end element. // Process sub-elements along the way. Loop: for { var savedOffset int if saveXML.IsValid() { savedOffset = p.savedOffset() } tok, err := p.Token() if err != nil { return err } switch t := tok.(type) { case StartElement: consumed := false if sv.IsValid() { consumed, err = p.unmarshalPath(tinfo, sv, nil, &t) if err != nil { return err } if !consumed && saveAny.IsValid() { consumed = true if err := p.unmarshal(saveAny, &t); err != nil { return err } } } if !consumed { if err := p.Skip(); err != nil { return err } } case EndElement: if saveXML.IsValid() { saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset] if saveXMLIndex == 0 { p.saved = nil } } break Loop case CharData: if saveData.IsValid() { data = append(data, t...) } case Comment: if saveComment.IsValid() { comment = append(comment, t...) } } } if saveData.IsValid() && saveData.CanInterface() && saveData.Type().Implements(textUnmarshalerType) { if err := saveData.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil { return err } saveData = reflect.Value{} } if saveData.IsValid() && saveData.CanAddr() { pv := saveData.Addr() if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) { if err := pv.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil { return err } saveData = reflect.Value{} } } if err := copyValue(saveData, data); err != nil { return err } switch t := saveComment; t.Kind() { case reflect.String: t.SetString(string(comment)) case reflect.Slice: t.Set(reflect.ValueOf(comment)) } switch t := saveXML; t.Kind() { case reflect.String: t.SetString(string(saveXMLData)) case reflect.Slice: t.Set(reflect.ValueOf(saveXMLData)) } return nil } func copyValue(dst reflect.Value, src []byte) (err error) { dst0 := dst if dst.Kind() == reflect.Ptr { if dst.IsNil() { dst.Set(reflect.New(dst.Type().Elem())) } dst = dst.Elem() } // Save accumulated data. switch dst.Kind() { case reflect.Invalid: // Probably a comment. default: return errors.New("cannot unmarshal into " + dst0.Type().String()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: itmp, err := strconv.ParseInt(string(src), 10, dst.Type().Bits()) if err != nil { return err } dst.SetInt(itmp) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: utmp, err := strconv.ParseUint(string(src), 10, dst.Type().Bits()) if err != nil { return err } dst.SetUint(utmp) case reflect.Float32, reflect.Float64: ftmp, err := strconv.ParseFloat(string(src), dst.Type().Bits()) if err != nil { return err } dst.SetFloat(ftmp) case reflect.Bool: value, err := strconv.ParseBool(strings.TrimSpace(string(src))) if err != nil { return err } dst.SetBool(value) case reflect.String: dst.SetString(string(src)) case reflect.Slice: if len(src) == 0 { // non-nil to flag presence src = []byte{} } dst.SetBytes(src) } return nil } // unmarshalPath walks down an XML structure looking for wanted // paths, and calls unmarshal on them. // The consumed result tells whether XML elements have been consumed // from the Decoder until start's matching end element, or if it's // still untouched because start is uninteresting for sv's fields. func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) { recurse := false Loop: for i := range tinfo.fields { finfo := &tinfo.fields[i] if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) || finfo.xmlns != "" && finfo.xmlns != start.Name.Space { continue } for j := range parents { if parents[j] != finfo.parents[j] { continue Loop } } if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local { // It's a perfect match, unmarshal the field. return true, p.unmarshal(finfo.value(sv), start) } if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local { // It's a prefix for the field. Break and recurse // since it's not ok for one field path to be itself // the prefix for another field path. recurse = true // We can reuse the same slice as long as we // don't try to append to it. parents = finfo.parents[:len(parents)+1] break } } if !recurse { // We have no business with this element. return false, nil } // The element is not a perfect match for any field, but one // or more fields have the path to this element as a parent // prefix. Recurse and attempt to match these. for { var tok Token tok, err = p.Token() if err != nil { return true, err } switch t := tok.(type) { case StartElement: consumed2, err := p.unmarshalPath(tinfo, sv, parents, &t) if err != nil { return true, err } if !consumed2 { if err := p.Skip(); err != nil { return true, err } } case EndElement: return true, nil } } } // Skip reads tokens until it has consumed the end element // matching the most recent start element already consumed. // It recurs if it encounters a start element, so it can be used to // skip nested structures. // It returns nil if it finds an end element matching the start // element; otherwise it returns an error describing the problem. func (d *Decoder) Skip() error { for { tok, err := d.Token() if err != nil { return err } switch tok.(type) { case StartElement: if err := d.Skip(); err != nil { return err } case EndElement: return nil } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/xml/read_test.go000066400000000000000000000505661264464372400266410ustar00rootroot00000000000000// 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 xml import ( "bytes" "fmt" "io" "reflect" "strings" "testing" "time" ) // Stripped down Atom feed data structures. func TestUnmarshalFeed(t *testing.T) { var f Feed if err := Unmarshal([]byte(atomFeedString), &f); err != nil { t.Fatalf("Unmarshal: %s", err) } if !reflect.DeepEqual(f, atomFeed) { t.Fatalf("have %#v\nwant %#v", f, atomFeed) } } // hget http://codereview.appspot.com/rss/mine/rsc const atomFeedString = ` Code Review - My issueshttp://codereview.appspot.com/rietveld<>rietveld: an attempt at pubsubhubbub 2009-10-04T01:35:58+00:00email-address-removedurn:md5:134d9179c41f806be79b3a5f7877d19a An attempt at adding pubsubhubbub support to Rietveld. http://code.google.com/p/pubsubhubbub http://code.google.com/p/rietveld/issues/detail?id=155 The server side of the protocol is trivial: 1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&gt; tag to all feeds that will be pubsubhubbubbed. 2. every time one of those feeds changes, tell the hub with a simple POST request. I have tested this by adding debug prints to a local hub server and checking that the server got the right publish requests. I can&#39;t quite get the server to work, but I think the bug is not in my code. I think that the server expects to be able to grab the feed and see the feed&#39;s actual URL in the link rel=&quot;self&quot;, but the default value for that drops the :port from the URL, and I cannot for the life of me figure out how to get the Atom generator deep inside django not to do that, or even where it is doing that, or even what code is running to generate the Atom feed. (I thought I knew but I added some assert False statements and it kept running!) Ignoring that particular problem, I would appreciate feedback on the right way to get the two values at the top of feeds.py marked NOTE(rsc). rietveld: correct tab handling 2009-10-03T23:02:17+00:00email-address-removedurn:md5:0a2a4f19bb815101f0ba2904aed7c35a This fixes the buggy tab rendering that can be seen at http://codereview.appspot.com/116075/diff/1/2 The fundamental problem was that the tab code was not being told what column the text began in, so it didn&#39;t know where to put the tab stops. Another problem was that some of the code assumed that string byte offsets were the same as column offsets, which is only true if there are no tabs. In the process of fixing this, I cleaned up the arguments to Fold and ExpandTabs and renamed them Break and _ExpandTabs so that I could be sure that I found all the call sites. I also wanted to verify that ExpandTabs was not being used from outside intra_region_diff.py. ` type Feed struct { XMLName Name `xml:"http://www.w3.org/2005/Atom feed"` Title string `xml:"title"` Id string `xml:"id"` Link []Link `xml:"link"` Updated time.Time `xml:"updated,attr"` Author Person `xml:"author"` Entry []Entry `xml:"entry"` } type Entry struct { Title string `xml:"title"` Id string `xml:"id"` Link []Link `xml:"link"` Updated time.Time `xml:"updated"` Author Person `xml:"author"` Summary Text `xml:"summary"` } type Link struct { Rel string `xml:"rel,attr,omitempty"` Href string `xml:"href,attr"` } type Person struct { Name string `xml:"name"` URI string `xml:"uri"` Email string `xml:"email"` InnerXML string `xml:",innerxml"` } type Text struct { Type string `xml:"type,attr,omitempty"` Body string `xml:",chardata"` } var atomFeed = Feed{ XMLName: Name{"http://www.w3.org/2005/Atom", "feed"}, Title: "Code Review - My issues", Link: []Link{ {Rel: "alternate", Href: "http://codereview.appspot.com/"}, {Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"}, }, Id: "http://codereview.appspot.com/", Updated: ParseTime("2009-10-04T01:35:58+00:00"), Author: Person{ Name: "rietveld<>", InnerXML: "rietveld<>", }, Entry: []Entry{ { Title: "rietveld: an attempt at pubsubhubbub\n", Link: []Link{ {Rel: "alternate", Href: "http://codereview.appspot.com/126085"}, }, Updated: ParseTime("2009-10-04T01:35:58+00:00"), Author: Person{ Name: "email-address-removed", InnerXML: "email-address-removed", }, Id: "urn:md5:134d9179c41f806be79b3a5f7877d19a", Summary: Text{ Type: "html", Body: ` An attempt at adding pubsubhubbub support to Rietveld. http://code.google.com/p/pubsubhubbub http://code.google.com/p/rietveld/issues/detail?id=155 The server side of the protocol is trivial: 1. add a <link rel="hub" href="hub-server"> tag to all feeds that will be pubsubhubbubbed. 2. every time one of those feeds changes, tell the hub with a simple POST request. I have tested this by adding debug prints to a local hub server and checking that the server got the right publish requests. I can't quite get the server to work, but I think the bug is not in my code. I think that the server expects to be able to grab the feed and see the feed's actual URL in the link rel="self", but the default value for that drops the :port from the URL, and I cannot for the life of me figure out how to get the Atom generator deep inside django not to do that, or even where it is doing that, or even what code is running to generate the Atom feed. (I thought I knew but I added some assert False statements and it kept running!) Ignoring that particular problem, I would appreciate feedback on the right way to get the two values at the top of feeds.py marked NOTE(rsc). `, }, }, { Title: "rietveld: correct tab handling\n", Link: []Link{ {Rel: "alternate", Href: "http://codereview.appspot.com/124106"}, }, Updated: ParseTime("2009-10-03T23:02:17+00:00"), Author: Person{ Name: "email-address-removed", InnerXML: "email-address-removed", }, Id: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a", Summary: Text{ Type: "html", Body: ` This fixes the buggy tab rendering that can be seen at http://codereview.appspot.com/116075/diff/1/2 The fundamental problem was that the tab code was not being told what column the text began in, so it didn't know where to put the tab stops. Another problem was that some of the code assumed that string byte offsets were the same as column offsets, which is only true if there are no tabs. In the process of fixing this, I cleaned up the arguments to Fold and ExpandTabs and renamed them Break and _ExpandTabs so that I could be sure that I found all the call sites. I also wanted to verify that ExpandTabs was not being used from outside intra_region_diff.py. `, }, }, }, } const pathTestString = ` 1 A B C D <_> E 2 ` type PathTestItem struct { Value string } type PathTestA struct { Items []PathTestItem `xml:">Item1"` Before, After string } type PathTestB struct { Other []PathTestItem `xml:"Items>Item1"` Before, After string } type PathTestC struct { Values1 []string `xml:"Items>Item1>Value"` Values2 []string `xml:"Items>Item2>Value"` Before, After string } type PathTestSet struct { Item1 []PathTestItem } type PathTestD struct { Other PathTestSet `xml:"Items"` Before, After string } type PathTestE struct { Underline string `xml:"Items>_>Value"` Before, After string } var pathTests = []interface{}{ &PathTestA{Items: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"}, &PathTestB{Other: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"}, &PathTestC{Values1: []string{"A", "C", "D"}, Values2: []string{"B"}, Before: "1", After: "2"}, &PathTestD{Other: PathTestSet{Item1: []PathTestItem{{"A"}, {"D"}}}, Before: "1", After: "2"}, &PathTestE{Underline: "E", Before: "1", After: "2"}, } func TestUnmarshalPaths(t *testing.T) { for _, pt := range pathTests { v := reflect.New(reflect.TypeOf(pt).Elem()).Interface() if err := Unmarshal([]byte(pathTestString), v); err != nil { t.Fatalf("Unmarshal: %s", err) } if !reflect.DeepEqual(v, pt) { t.Fatalf("have %#v\nwant %#v", v, pt) } } } type BadPathTestA struct { First string `xml:"items>item1"` Other string `xml:"items>item2"` Second string `xml:"items"` } type BadPathTestB struct { Other string `xml:"items>item2>value"` First string `xml:"items>item1"` Second string `xml:"items>item1>value"` } type BadPathTestC struct { First string Second string `xml:"First"` } type BadPathTestD struct { BadPathEmbeddedA BadPathEmbeddedB } type BadPathEmbeddedA struct { First string } type BadPathEmbeddedB struct { Second string `xml:"First"` } var badPathTests = []struct { v, e interface{} }{ {&BadPathTestA{}, &TagPathError{reflect.TypeOf(BadPathTestA{}), "First", "items>item1", "Second", "items"}}, {&BadPathTestB{}, &TagPathError{reflect.TypeOf(BadPathTestB{}), "First", "items>item1", "Second", "items>item1>value"}}, {&BadPathTestC{}, &TagPathError{reflect.TypeOf(BadPathTestC{}), "First", "", "Second", "First"}}, {&BadPathTestD{}, &TagPathError{reflect.TypeOf(BadPathTestD{}), "First", "", "Second", "First"}}, } func TestUnmarshalBadPaths(t *testing.T) { for _, tt := range badPathTests { err := Unmarshal([]byte(pathTestString), tt.v) if !reflect.DeepEqual(err, tt.e) { t.Fatalf("Unmarshal with %#v didn't fail properly:\nhave %#v,\nwant %#v", tt.v, err, tt.e) } } } const OK = "OK" const withoutNameTypeData = ` ` type TestThree struct { XMLName Name `xml:"Test3"` Attr string `xml:",attr"` } func TestUnmarshalWithoutNameType(t *testing.T) { var x TestThree if err := Unmarshal([]byte(withoutNameTypeData), &x); err != nil { t.Fatalf("Unmarshal: %s", err) } if x.Attr != OK { t.Fatalf("have %v\nwant %v", x.Attr, OK) } } func TestUnmarshalAttr(t *testing.T) { type ParamVal struct { Int int `xml:"int,attr"` } type ParamPtr struct { Int *int `xml:"int,attr"` } type ParamStringPtr struct { Int *string `xml:"int,attr"` } x := []byte(``) p1 := &ParamPtr{} if err := Unmarshal(x, p1); err != nil { t.Fatalf("Unmarshal: %s", err) } if p1.Int == nil { t.Fatalf("Unmarshal failed in to *int field") } else if *p1.Int != 1 { t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p1.Int, 1) } p2 := &ParamVal{} if err := Unmarshal(x, p2); err != nil { t.Fatalf("Unmarshal: %s", err) } if p2.Int != 1 { t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p2.Int, 1) } p3 := &ParamStringPtr{} if err := Unmarshal(x, p3); err != nil { t.Fatalf("Unmarshal: %s", err) } if p3.Int == nil { t.Fatalf("Unmarshal failed in to *string field") } else if *p3.Int != "1" { t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p3.Int, 1) } } type Tables struct { HTable string `xml:"http://www.w3.org/TR/html4/ table"` FTable string `xml:"http://www.w3schools.com/furniture table"` } var tables = []struct { xml string tab Tables ns string }{ { xml: `` + `hello
    ` + `world
    ` + `
    `, tab: Tables{"hello", "world"}, }, { xml: `` + `world
    ` + `hello
    ` + `
    `, tab: Tables{"hello", "world"}, }, { xml: `` + `world` + `hello` + ``, tab: Tables{"hello", "world"}, }, { xml: `` + `bogus
    ` + `
    `, tab: Tables{}, }, { xml: `` + `only
    ` + `
    `, tab: Tables{HTable: "only"}, ns: "http://www.w3.org/TR/html4/", }, { xml: `` + `only
    ` + `
    `, tab: Tables{FTable: "only"}, ns: "http://www.w3schools.com/furniture", }, { xml: `` + `only
    ` + `
    `, tab: Tables{}, ns: "something else entirely", }, } func TestUnmarshalNS(t *testing.T) { for i, tt := range tables { var dst Tables var err error if tt.ns != "" { d := NewDecoder(strings.NewReader(tt.xml)) d.DefaultSpace = tt.ns err = d.Decode(&dst) } else { err = Unmarshal([]byte(tt.xml), &dst) } if err != nil { t.Errorf("#%d: Unmarshal: %v", i, err) continue } want := tt.tab if dst != want { t.Errorf("#%d: dst=%+v, want %+v", i, dst, want) } } } func TestRoundTrip(t *testing.T) { // From issue 7535 const s = `` in := bytes.NewBufferString(s) for i := 0; i < 10; i++ { out := &bytes.Buffer{} d := NewDecoder(in) e := NewEncoder(out) for { t, err := d.Token() if err == io.EOF { break } if err != nil { fmt.Println("failed:", err) return } e.EncodeToken(t) } e.Flush() in = out } if got := in.String(); got != s { t.Errorf("have: %q\nwant: %q\n", got, s) } } func TestMarshalNS(t *testing.T) { dst := Tables{"hello", "world"} data, err := Marshal(&dst) if err != nil { t.Fatalf("Marshal: %v", err) } want := `hello
    world
    ` str := string(data) if str != want { t.Errorf("have: %q\nwant: %q\n", str, want) } } type TableAttrs struct { TAttr TAttr } type TAttr struct { HTable string `xml:"http://www.w3.org/TR/html4/ table,attr"` FTable string `xml:"http://www.w3schools.com/furniture table,attr"` Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"` Other1 string `xml:"http://golang.org/xml/ other,attr,omitempty"` Other2 string `xml:"http://golang.org/xmlfoo/ other,attr,omitempty"` Other3 string `xml:"http://golang.org/json/ other,attr,omitempty"` Other4 string `xml:"http://golang.org/2/json/ other,attr,omitempty"` } var tableAttrs = []struct { xml string tab TableAttrs ns string }{ { xml: ``, tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}}, }, { xml: ``, tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}}, }, { xml: ``, tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}}, }, { // Default space does not apply to attribute names. xml: ``, tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}}, }, { // Default space does not apply to attribute names. xml: ``, tab: TableAttrs{TAttr{HTable: "", FTable: "world"}}, }, { xml: ``, tab: TableAttrs{}, }, { // Default space does not apply to attribute names. xml: ``, tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}}, ns: "http://www.w3schools.com/furniture", }, { // Default space does not apply to attribute names. xml: ``, tab: TableAttrs{TAttr{HTable: "", FTable: "world"}}, ns: "http://www.w3.org/TR/html4/", }, { xml: ``, tab: TableAttrs{}, ns: "something else entirely", }, } func TestUnmarshalNSAttr(t *testing.T) { for i, tt := range tableAttrs { var dst TableAttrs var err error if tt.ns != "" { d := NewDecoder(strings.NewReader(tt.xml)) d.DefaultSpace = tt.ns err = d.Decode(&dst) } else { err = Unmarshal([]byte(tt.xml), &dst) } if err != nil { t.Errorf("#%d: Unmarshal: %v", i, err) continue } want := tt.tab if dst != want { t.Errorf("#%d: dst=%+v, want %+v", i, dst, want) } } } func TestMarshalNSAttr(t *testing.T) { src := TableAttrs{TAttr{"hello", "world", "en_US", "other1", "other2", "other3", "other4"}} data, err := Marshal(&src) if err != nil { t.Fatalf("Marshal: %v", err) } want := `` str := string(data) if str != want { t.Errorf("Marshal:\nhave: %#q\nwant: %#q\n", str, want) } var dst TableAttrs if err := Unmarshal(data, &dst); err != nil { t.Errorf("Unmarshal: %v", err) } if dst != src { t.Errorf("Unmarshal = %q, want %q", dst, src) } } type MyCharData struct { body string } func (m *MyCharData) UnmarshalXML(d *Decoder, start StartElement) error { for { t, err := d.Token() if err == io.EOF { // found end of element break } if err != nil { return err } if char, ok := t.(CharData); ok { m.body += string(char) } } return nil } var _ Unmarshaler = (*MyCharData)(nil) func (m *MyCharData) UnmarshalXMLAttr(attr Attr) error { panic("must not call") } type MyAttr struct { attr string } func (m *MyAttr) UnmarshalXMLAttr(attr Attr) error { m.attr = attr.Value return nil } var _ UnmarshalerAttr = (*MyAttr)(nil) type MyStruct struct { Data *MyCharData Attr *MyAttr `xml:",attr"` Data2 MyCharData Attr2 MyAttr `xml:",attr"` } func TestUnmarshaler(t *testing.T) { xml := ` hello world howdy world ` var m MyStruct if err := Unmarshal([]byte(xml), &m); err != nil { t.Fatal(err) } if m.Data == nil || m.Attr == nil || m.Data.body != "hello world" || m.Attr.attr != "attr1" || m.Data2.body != "howdy world" || m.Attr2.attr != "attr2" { t.Errorf("m=%#+v\n", m) } } type Pea struct { Cotelydon string } type Pod struct { Pea interface{} `xml:"Pea"` } // https://golang.org/issue/6836 func TestUnmarshalIntoInterface(t *testing.T) { pod := new(Pod) pod.Pea = new(Pea) xml := `Green stuff` err := Unmarshal([]byte(xml), pod) if err != nil { t.Fatalf("failed to unmarshal %q: %v", xml, err) } pea, ok := pod.Pea.(*Pea) if !ok { t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea) } have, want := pea.Cotelydon, "Green stuff" if have != want { t.Errorf("failed to unmarshal into interface, have %q want %q", have, want) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/xml/typeinfo.go000066400000000000000000000230071264464372400265120ustar00rootroot00000000000000// 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 xml import ( "fmt" "reflect" "strings" "sync" ) // typeInfo holds details for the xml representation of a type. type typeInfo struct { xmlname *fieldInfo fields []fieldInfo } // fieldInfo holds details for the xml representation of a single field. type fieldInfo struct { idx []int name string xmlns string flags fieldFlags parents []string } type fieldFlags int const ( fElement fieldFlags = 1 << iota fAttr fCharData fInnerXml fComment fAny fOmitEmpty fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny ) var tinfoMap = make(map[reflect.Type]*typeInfo) var tinfoLock sync.RWMutex var nameType = reflect.TypeOf(Name{}) // getTypeInfo returns the typeInfo structure with details necessary // for marshalling and unmarshalling typ. func getTypeInfo(typ reflect.Type) (*typeInfo, error) { tinfoLock.RLock() tinfo, ok := tinfoMap[typ] tinfoLock.RUnlock() if ok { return tinfo, nil } tinfo = &typeInfo{} if typ.Kind() == reflect.Struct && typ != nameType { n := typ.NumField() for i := 0; i < n; i++ { f := typ.Field(i) if f.PkgPath != "" || f.Tag.Get("xml") == "-" { continue // Private field } // For embedded structs, embed its fields. if f.Anonymous { t := f.Type if t.Kind() == reflect.Ptr { t = t.Elem() } if t.Kind() == reflect.Struct { inner, err := getTypeInfo(t) if err != nil { return nil, err } if tinfo.xmlname == nil { tinfo.xmlname = inner.xmlname } for _, finfo := range inner.fields { finfo.idx = append([]int{i}, finfo.idx...) if err := addFieldInfo(typ, tinfo, &finfo); err != nil { return nil, err } } continue } } finfo, err := structFieldInfo(typ, &f) if err != nil { return nil, err } if f.Name == "XMLName" { tinfo.xmlname = finfo continue } // Add the field if it doesn't conflict with other fields. if err := addFieldInfo(typ, tinfo, finfo); err != nil { return nil, err } } } tinfoLock.Lock() tinfoMap[typ] = tinfo tinfoLock.Unlock() return tinfo, nil } // structFieldInfo builds and returns a fieldInfo for f. func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, error) { finfo := &fieldInfo{idx: f.Index} // Split the tag from the xml namespace if necessary. tag := f.Tag.Get("xml") if i := strings.Index(tag, " "); i >= 0 { finfo.xmlns, tag = tag[:i], tag[i+1:] } // Parse flags. tokens := strings.Split(tag, ",") if len(tokens) == 1 { finfo.flags = fElement } else { tag = tokens[0] for _, flag := range tokens[1:] { switch flag { case "attr": finfo.flags |= fAttr case "chardata": finfo.flags |= fCharData case "innerxml": finfo.flags |= fInnerXml case "comment": finfo.flags |= fComment case "any": finfo.flags |= fAny case "omitempty": finfo.flags |= fOmitEmpty } } // Validate the flags used. valid := true switch mode := finfo.flags & fMode; mode { case 0: finfo.flags |= fElement case fAttr, fCharData, fInnerXml, fComment, fAny: if f.Name == "XMLName" || tag != "" && mode != fAttr { valid = false } default: // This will also catch multiple modes in a single field. valid = false } if finfo.flags&fMode == fAny { finfo.flags |= fElement } if finfo.flags&fOmitEmpty != 0 && finfo.flags&(fElement|fAttr) == 0 { valid = false } if !valid { return nil, fmt.Errorf("xml: invalid tag in field %s of type %s: %q", f.Name, typ, f.Tag.Get("xml")) } } // Use of xmlns without a name is not allowed. if finfo.xmlns != "" && tag == "" { return nil, fmt.Errorf("xml: namespace without name in field %s of type %s: %q", f.Name, typ, f.Tag.Get("xml")) } if f.Name == "XMLName" { // The XMLName field records the XML element name. Don't // process it as usual because its name should default to // empty rather than to the field name. finfo.name = tag return finfo, nil } if tag == "" { // If the name part of the tag is completely empty, get // default from XMLName of underlying struct if feasible, // or field name otherwise. if xmlname := lookupXMLName(f.Type); xmlname != nil { finfo.xmlns, finfo.name = xmlname.xmlns, xmlname.name } else { finfo.name = f.Name } return finfo, nil } if finfo.xmlns == "" && finfo.flags&fAttr == 0 { // If it's an element no namespace specified, get the default // from the XMLName of enclosing struct if possible. if xmlname := lookupXMLName(typ); xmlname != nil { finfo.xmlns = xmlname.xmlns } } // Prepare field name and parents. parents := strings.Split(tag, ">") if parents[0] == "" { parents[0] = f.Name } if parents[len(parents)-1] == "" { return nil, fmt.Errorf("xml: trailing '>' in field %s of type %s", f.Name, typ) } finfo.name = parents[len(parents)-1] if len(parents) > 1 { if (finfo.flags & fElement) == 0 { return nil, fmt.Errorf("xml: %s chain not valid with %s flag", tag, strings.Join(tokens[1:], ",")) } finfo.parents = parents[:len(parents)-1] } // If the field type has an XMLName field, the names must match // so that the behavior of both marshalling and unmarshalling // is straightforward and unambiguous. if finfo.flags&fElement != 0 { ftyp := f.Type xmlname := lookupXMLName(ftyp) if xmlname != nil && xmlname.name != finfo.name { return nil, fmt.Errorf("xml: name %q in tag of %s.%s conflicts with name %q in %s.XMLName", finfo.name, typ, f.Name, xmlname.name, ftyp) } } return finfo, nil } // lookupXMLName returns the fieldInfo for typ's XMLName field // in case it exists and has a valid xml field tag, otherwise // it returns nil. func lookupXMLName(typ reflect.Type) (xmlname *fieldInfo) { for typ.Kind() == reflect.Ptr { typ = typ.Elem() } if typ.Kind() != reflect.Struct { return nil } for i, n := 0, typ.NumField(); i < n; i++ { f := typ.Field(i) if f.Name != "XMLName" { continue } finfo, err := structFieldInfo(typ, &f) if finfo.name != "" && err == nil { return finfo } // Also consider errors as a non-existent field tag // and let getTypeInfo itself report the error. break } return nil } func min(a, b int) int { if a <= b { return a } return b } // addFieldInfo adds finfo to tinfo.fields if there are no // conflicts, or if conflicts arise from previous fields that were // obtained from deeper embedded structures than finfo. In the latter // case, the conflicting entries are dropped. // A conflict occurs when the path (parent + name) to a field is // itself a prefix of another path, or when two paths match exactly. // It is okay for field paths to share a common, shorter prefix. func addFieldInfo(typ reflect.Type, tinfo *typeInfo, newf *fieldInfo) error { var conflicts []int Loop: // First, figure all conflicts. Most working code will have none. for i := range tinfo.fields { oldf := &tinfo.fields[i] if oldf.flags&fMode != newf.flags&fMode { continue } if oldf.xmlns != "" && newf.xmlns != "" && oldf.xmlns != newf.xmlns { continue } minl := min(len(newf.parents), len(oldf.parents)) for p := 0; p < minl; p++ { if oldf.parents[p] != newf.parents[p] { continue Loop } } if len(oldf.parents) > len(newf.parents) { if oldf.parents[len(newf.parents)] == newf.name { conflicts = append(conflicts, i) } } else if len(oldf.parents) < len(newf.parents) { if newf.parents[len(oldf.parents)] == oldf.name { conflicts = append(conflicts, i) } } else { if newf.name == oldf.name { conflicts = append(conflicts, i) } } } // Without conflicts, add the new field and return. if conflicts == nil { tinfo.fields = append(tinfo.fields, *newf) return nil } // If any conflict is shallower, ignore the new field. // This matches the Go field resolution on embedding. for _, i := range conflicts { if len(tinfo.fields[i].idx) < len(newf.idx) { return nil } } // Otherwise, if any of them is at the same depth level, it's an error. for _, i := range conflicts { oldf := &tinfo.fields[i] if len(oldf.idx) == len(newf.idx) { f1 := typ.FieldByIndex(oldf.idx) f2 := typ.FieldByIndex(newf.idx) return &TagPathError{typ, f1.Name, f1.Tag.Get("xml"), f2.Name, f2.Tag.Get("xml")} } } // Otherwise, the new field is shallower, and thus takes precedence, // so drop the conflicting fields from tinfo and append the new one. for c := len(conflicts) - 1; c >= 0; c-- { i := conflicts[c] copy(tinfo.fields[i:], tinfo.fields[i+1:]) tinfo.fields = tinfo.fields[:len(tinfo.fields)-1] } tinfo.fields = append(tinfo.fields, *newf) return nil } // A TagPathError represents an error in the unmarshalling process // caused by the use of field tags with conflicting paths. type TagPathError struct { Struct reflect.Type Field1, Tag1 string Field2, Tag2 string } func (e *TagPathError) Error() string { return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2) } // value returns v's field value corresponding to finfo. // It's equivalent to v.FieldByIndex(finfo.idx), but initializes // and dereferences pointers as necessary. func (finfo *fieldInfo) value(v reflect.Value) reflect.Value { for i, x := range finfo.idx { if i > 0 { t := v.Type() if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct { if v.IsNil() { v.Set(reflect.New(v.Type().Elem())) } v = v.Elem() } } v = v.Field(x) } return v } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/internal/xml/xml.go000066400000000000000000001317251264464372400254640ustar00rootroot00000000000000// 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 xml implements a simple XML 1.0 parser that // understands XML name spaces. package xml // References: // Annotated XML spec: http://www.xml.com/axml/testaxml.htm // XML name spaces: http://www.w3.org/TR/REC-xml-names/ // TODO(rsc): // Test error handling. import ( "bufio" "bytes" "errors" "fmt" "io" "strconv" "strings" "unicode" "unicode/utf8" ) // A SyntaxError represents a syntax error in the XML input stream. type SyntaxError struct { Msg string Line int } func (e *SyntaxError) Error() string { return "XML syntax error on line " + strconv.Itoa(e.Line) + ": " + e.Msg } // A Name represents an XML name (Local) annotated with a name space // identifier (Space). In tokens returned by Decoder.Token, the Space // identifier is given as a canonical URL, not the short prefix used in // the document being parsed. // // As a special case, XML namespace declarations will use the literal // string "xmlns" for the Space field instead of the fully resolved URL. // See Encoder.EncodeToken for more information on namespace encoding // behaviour. type Name struct { Space, Local string } // isNamespace reports whether the name is a namespace-defining name. func (name Name) isNamespace() bool { return name.Local == "xmlns" || name.Space == "xmlns" } // An Attr represents an attribute in an XML element (Name=Value). type Attr struct { Name Name Value string } // A Token is an interface holding one of the token types: // StartElement, EndElement, CharData, Comment, ProcInst, or Directive. type Token interface{} // A StartElement represents an XML start element. type StartElement struct { Name Name Attr []Attr } func (e StartElement) Copy() StartElement { attrs := make([]Attr, len(e.Attr)) copy(attrs, e.Attr) e.Attr = attrs return e } // End returns the corresponding XML end element. func (e StartElement) End() EndElement { return EndElement{e.Name} } // setDefaultNamespace sets the namespace of the element // as the default for all elements contained within it. func (e *StartElement) setDefaultNamespace() { if e.Name.Space == "" { // If there's no namespace on the element, don't // set the default. Strictly speaking this might be wrong, as // we can't tell if the element had no namespace set // or was just using the default namespace. return } // Don't add a default name space if there's already one set. for _, attr := range e.Attr { if attr.Name.Space == "" && attr.Name.Local == "xmlns" { return } } e.Attr = append(e.Attr, Attr{ Name: Name{ Local: "xmlns", }, Value: e.Name.Space, }) } // An EndElement represents an XML end element. type EndElement struct { Name Name } // A CharData represents XML character data (raw text), // in which XML escape sequences have been replaced by // the characters they represent. type CharData []byte func makeCopy(b []byte) []byte { b1 := make([]byte, len(b)) copy(b1, b) return b1 } func (c CharData) Copy() CharData { return CharData(makeCopy(c)) } // A Comment represents an XML comment of the form . // The bytes do not include the comment markers. type Comment []byte func (c Comment) Copy() Comment { return Comment(makeCopy(c)) } // A ProcInst represents an XML processing instruction of the form type ProcInst struct { Target string Inst []byte } func (p ProcInst) Copy() ProcInst { p.Inst = makeCopy(p.Inst) return p } // A Directive represents an XML directive of the form . // The bytes do not include the markers. type Directive []byte func (d Directive) Copy() Directive { return Directive(makeCopy(d)) } // CopyToken returns a copy of a Token. func CopyToken(t Token) Token { switch v := t.(type) { case CharData: return v.Copy() case Comment: return v.Copy() case Directive: return v.Copy() case ProcInst: return v.Copy() case StartElement: return v.Copy() } return t } // A Decoder represents an XML parser reading a particular input stream. // The parser assumes that its input is encoded in UTF-8. type Decoder struct { // Strict defaults to true, enforcing the requirements // of the XML specification. // If set to false, the parser allows input containing common // mistakes: // * If an element is missing an end tag, the parser invents // end tags as necessary to keep the return values from Token // properly balanced. // * In attribute values and character data, unknown or malformed // character entities (sequences beginning with &) are left alone. // // Setting: // // d.Strict = false; // d.AutoClose = HTMLAutoClose; // d.Entity = HTMLEntity // // creates a parser that can handle typical HTML. // // Strict mode does not enforce the requirements of the XML name spaces TR. // In particular it does not reject name space tags using undefined prefixes. // Such tags are recorded with the unknown prefix as the name space URL. Strict bool // When Strict == false, AutoClose indicates a set of elements to // consider closed immediately after they are opened, regardless // of whether an end element is present. AutoClose []string // Entity can be used to map non-standard entity names to string replacements. // The parser behaves as if these standard mappings are present in the map, // regardless of the actual map content: // // "lt": "<", // "gt": ">", // "amp": "&", // "apos": "'", // "quot": `"`, Entity map[string]string // CharsetReader, if non-nil, defines a function to generate // charset-conversion readers, converting from the provided // non-UTF-8 charset into UTF-8. If CharsetReader is nil or // returns an error, parsing stops with an error. One of the // the CharsetReader's result values must be non-nil. CharsetReader func(charset string, input io.Reader) (io.Reader, error) // DefaultSpace sets the default name space used for unadorned tags, // as if the entire XML stream were wrapped in an element containing // the attribute xmlns="DefaultSpace". DefaultSpace string r io.ByteReader buf bytes.Buffer saved *bytes.Buffer stk *stack free *stack needClose bool toClose Name nextToken Token nextByte int ns map[string]string err error line int offset int64 unmarshalDepth int } // NewDecoder creates a new XML parser reading from r. // If r does not implement io.ByteReader, NewDecoder will // do its own buffering. func NewDecoder(r io.Reader) *Decoder { d := &Decoder{ ns: make(map[string]string), nextByte: -1, line: 1, Strict: true, } d.switchToReader(r) return d } // Token returns the next XML token in the input stream. // At the end of the input stream, Token returns nil, io.EOF. // // Slices of bytes in the returned token data refer to the // parser's internal buffer and remain valid only until the next // call to Token. To acquire a copy of the bytes, call CopyToken // or the token's Copy method. // // Token expands self-closing elements such as
    // into separate start and end elements returned by successive calls. // // Token guarantees that the StartElement and EndElement // tokens it returns are properly nested and matched: // if Token encounters an unexpected end element, // it will return an error. // // Token implements XML name spaces as described by // http://www.w3.org/TR/REC-xml-names/. Each of the // Name structures contained in the Token has the Space // set to the URL identifying its name space when known. // If Token encounters an unrecognized name space prefix, // it uses the prefix as the Space rather than report an error. func (d *Decoder) Token() (t Token, err error) { if d.stk != nil && d.stk.kind == stkEOF { err = io.EOF return } if d.nextToken != nil { t = d.nextToken d.nextToken = nil } else if t, err = d.rawToken(); err != nil { return } if !d.Strict { if t1, ok := d.autoClose(t); ok { d.nextToken = t t = t1 } } switch t1 := t.(type) { case StartElement: // In XML name spaces, the translations listed in the // attributes apply to the element name and // to the other attribute names, so process // the translations first. for _, a := range t1.Attr { if a.Name.Space == "xmlns" { v, ok := d.ns[a.Name.Local] d.pushNs(a.Name.Local, v, ok) d.ns[a.Name.Local] = a.Value } if a.Name.Space == "" && a.Name.Local == "xmlns" { // Default space for untagged names v, ok := d.ns[""] d.pushNs("", v, ok) d.ns[""] = a.Value } } d.translate(&t1.Name, true) for i := range t1.Attr { d.translate(&t1.Attr[i].Name, false) } d.pushElement(t1.Name) t = t1 case EndElement: d.translate(&t1.Name, true) if !d.popElement(&t1) { return nil, d.err } t = t1 } return } const xmlURL = "http://www.w3.org/XML/1998/namespace" // Apply name space translation to name n. // The default name space (for Space=="") // applies only to element names, not to attribute names. func (d *Decoder) translate(n *Name, isElementName bool) { switch { case n.Space == "xmlns": return case n.Space == "" && !isElementName: return case n.Space == "xml": n.Space = xmlURL case n.Space == "" && n.Local == "xmlns": return } if v, ok := d.ns[n.Space]; ok { n.Space = v } else if n.Space == "" { n.Space = d.DefaultSpace } } func (d *Decoder) switchToReader(r io.Reader) { // Get efficient byte at a time reader. // Assume that if reader has its own // ReadByte, it's efficient enough. // Otherwise, use bufio. if rb, ok := r.(io.ByteReader); ok { d.r = rb } else { d.r = bufio.NewReader(r) } } // Parsing state - stack holds old name space translations // and the current set of open elements. The translations to pop when // ending a given tag are *below* it on the stack, which is // more work but forced on us by XML. type stack struct { next *stack kind int name Name ok bool } const ( stkStart = iota stkNs stkEOF ) func (d *Decoder) push(kind int) *stack { s := d.free if s != nil { d.free = s.next } else { s = new(stack) } s.next = d.stk s.kind = kind d.stk = s return s } func (d *Decoder) pop() *stack { s := d.stk if s != nil { d.stk = s.next s.next = d.free d.free = s } return s } // Record that after the current element is finished // (that element is already pushed on the stack) // Token should return EOF until popEOF is called. func (d *Decoder) pushEOF() { // Walk down stack to find Start. // It might not be the top, because there might be stkNs // entries above it. start := d.stk for start.kind != stkStart { start = start.next } // The stkNs entries below a start are associated with that // element too; skip over them. for start.next != nil && start.next.kind == stkNs { start = start.next } s := d.free if s != nil { d.free = s.next } else { s = new(stack) } s.kind = stkEOF s.next = start.next start.next = s } // Undo a pushEOF. // The element must have been finished, so the EOF should be at the top of the stack. func (d *Decoder) popEOF() bool { if d.stk == nil || d.stk.kind != stkEOF { return false } d.pop() return true } // Record that we are starting an element with the given name. func (d *Decoder) pushElement(name Name) { s := d.push(stkStart) s.name = name } // Record that we are changing the value of ns[local]. // The old value is url, ok. func (d *Decoder) pushNs(local string, url string, ok bool) { s := d.push(stkNs) s.name.Local = local s.name.Space = url s.ok = ok } // Creates a SyntaxError with the current line number. func (d *Decoder) syntaxError(msg string) error { return &SyntaxError{Msg: msg, Line: d.line} } // Record that we are ending an element with the given name. // The name must match the record at the top of the stack, // which must be a pushElement record. // After popping the element, apply any undo records from // the stack to restore the name translations that existed // before we saw this element. func (d *Decoder) popElement(t *EndElement) bool { s := d.pop() name := t.Name switch { case s == nil || s.kind != stkStart: d.err = d.syntaxError("unexpected end element ") return false case s.name.Local != name.Local: if !d.Strict { d.needClose = true d.toClose = t.Name t.Name = s.name return true } d.err = d.syntaxError("element <" + s.name.Local + "> closed by ") return false case s.name.Space != name.Space: d.err = d.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space + "closed by in space " + name.Space) return false } // Pop stack until a Start or EOF is on the top, undoing the // translations that were associated with the element we just closed. for d.stk != nil && d.stk.kind != stkStart && d.stk.kind != stkEOF { s := d.pop() if s.ok { d.ns[s.name.Local] = s.name.Space } else { delete(d.ns, s.name.Local) } } return true } // If the top element on the stack is autoclosing and // t is not the end tag, invent the end tag. func (d *Decoder) autoClose(t Token) (Token, bool) { if d.stk == nil || d.stk.kind != stkStart { return nil, false } name := strings.ToLower(d.stk.name.Local) for _, s := range d.AutoClose { if strings.ToLower(s) == name { // This one should be auto closed if t doesn't close it. et, ok := t.(EndElement) if !ok || et.Name.Local != name { return EndElement{d.stk.name}, true } break } } return nil, false } var errRawToken = errors.New("xml: cannot use RawToken from UnmarshalXML method") // RawToken is like Token but does not verify that // start and end elements match and does not translate // name space prefixes to their corresponding URLs. func (d *Decoder) RawToken() (Token, error) { if d.unmarshalDepth > 0 { return nil, errRawToken } return d.rawToken() } func (d *Decoder) rawToken() (Token, error) { if d.err != nil { return nil, d.err } if d.needClose { // The last element we read was self-closing and // we returned just the StartElement half. // Return the EndElement half now. d.needClose = false return EndElement{d.toClose}, nil } b, ok := d.getc() if !ok { return nil, d.err } if b != '<' { // Text section. d.ungetc(b) data := d.text(-1, false) if data == nil { return nil, d.err } return CharData(data), nil } if b, ok = d.mustgetc(); !ok { return nil, d.err } switch b { case '/': // ' { d.err = d.syntaxError("invalid characters between ") return nil, d.err } return EndElement{name}, nil case '?': // ' { break } b0 = b } data := d.buf.Bytes() data = data[0 : len(data)-2] // chop ?> if target == "xml" { content := string(data) ver := procInst("version", content) if ver != "" && ver != "1.0" { d.err = fmt.Errorf("xml: unsupported version %q; only version 1.0 is supported", ver) return nil, d.err } enc := procInst("encoding", content) if enc != "" && enc != "utf-8" && enc != "UTF-8" { if d.CharsetReader == nil { d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc) return nil, d.err } newr, err := d.CharsetReader(enc, d.r.(io.Reader)) if err != nil { d.err = fmt.Errorf("xml: opening charset %q: %v", enc, err) return nil, d.err } if newr == nil { panic("CharsetReader returned a nil Reader for charset " + enc) } d.switchToReader(newr) } } return ProcInst{target, data}, nil case '!': // ' { break } b0, b1 = b1, b } data := d.buf.Bytes() data = data[0 : len(data)-3] // chop --> return Comment(data), nil case '[': // . data := d.text(-1, true) if data == nil { return nil, d.err } return CharData(data), nil } // Probably a directive: , , etc. // We don't care, but accumulate for caller. Quoted angle // brackets do not count for nesting. d.buf.Reset() d.buf.WriteByte(b) inquote := uint8(0) depth := 0 for { if b, ok = d.mustgetc(); !ok { return nil, d.err } if inquote == 0 && b == '>' && depth == 0 { break } HandleB: d.buf.WriteByte(b) switch { case b == inquote: inquote = 0 case inquote != 0: // in quotes, no special action case b == '\'' || b == '"': inquote = b case b == '>' && inquote == 0: depth-- case b == '<' && inquote == 0: // Look for ` var testEntity = map[string]string{"何": "What", "is-it": "is it?"} var rawTokens = []Token{ CharData("\n"), ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)}, CharData("\n"), Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`), CharData("\n"), StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}}, CharData("\n "), StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}, CharData("World <>'\" 白鵬翔"), EndElement{Name{"", "hello"}}, CharData("\n "), StartElement{Name{"", "query"}, []Attr{}}, CharData("What is it?"), EndElement{Name{"", "query"}}, CharData("\n "), StartElement{Name{"", "goodbye"}, []Attr{}}, EndElement{Name{"", "goodbye"}}, CharData("\n "), StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}}, CharData("\n "), StartElement{Name{"", "inner"}, []Attr{}}, EndElement{Name{"", "inner"}}, CharData("\n "), EndElement{Name{"", "outer"}}, CharData("\n "), StartElement{Name{"tag", "name"}, []Attr{}}, CharData("\n "), CharData("Some text here."), CharData("\n "), EndElement{Name{"tag", "name"}}, CharData("\n"), EndElement{Name{"", "body"}}, Comment(" missing final newline "), } var cookedTokens = []Token{ CharData("\n"), ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)}, CharData("\n"), Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`), CharData("\n"), StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}}, CharData("\n "), StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}, CharData("World <>'\" 白鵬翔"), EndElement{Name{"ns2", "hello"}}, CharData("\n "), StartElement{Name{"ns2", "query"}, []Attr{}}, CharData("What is it?"), EndElement{Name{"ns2", "query"}}, CharData("\n "), StartElement{Name{"ns2", "goodbye"}, []Attr{}}, EndElement{Name{"ns2", "goodbye"}}, CharData("\n "), StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}}, CharData("\n "), StartElement{Name{"ns2", "inner"}, []Attr{}}, EndElement{Name{"ns2", "inner"}}, CharData("\n "), EndElement{Name{"ns2", "outer"}}, CharData("\n "), StartElement{Name{"ns3", "name"}, []Attr{}}, CharData("\n "), CharData("Some text here."), CharData("\n "), EndElement{Name{"ns3", "name"}}, CharData("\n"), EndElement{Name{"ns2", "body"}}, Comment(" missing final newline "), } const testInputAltEncoding = ` VALUE` var rawTokensAltEncoding = []Token{ CharData("\n"), ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)}, CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, CharData("value"), EndElement{Name{"", "tag"}}, } var xmlInput = []string{ // unexpected EOF cases "<", "", "", "", // "", // let the Token() caller handle "", "", "", "", " c;", "", "", "", // "", // let the Token() caller handle "", "", "cdata]]>", } func TestRawToken(t *testing.T) { d := NewDecoder(strings.NewReader(testInput)) d.Entity = testEntity testRawToken(t, d, testInput, rawTokens) } const nonStrictInput = ` non&entity &unknown;entity { &#zzz; &ãªã¾ãˆ3; <-gt; &; &0a; ` var nonStringEntity = map[string]string{"": "oops!", "0a": "oops!"} var nonStrictTokens = []Token{ CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, CharData("non&entity"), EndElement{Name{"", "tag"}}, CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, CharData("&unknown;entity"), EndElement{Name{"", "tag"}}, CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, CharData("{"), EndElement{Name{"", "tag"}}, CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, CharData("&#zzz;"), EndElement{Name{"", "tag"}}, CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, CharData("&ãªã¾ãˆ3;"), EndElement{Name{"", "tag"}}, CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, CharData("<-gt;"), EndElement{Name{"", "tag"}}, CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, CharData("&;"), EndElement{Name{"", "tag"}}, CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, CharData("&0a;"), EndElement{Name{"", "tag"}}, CharData("\n"), } func TestNonStrictRawToken(t *testing.T) { d := NewDecoder(strings.NewReader(nonStrictInput)) d.Strict = false testRawToken(t, d, nonStrictInput, nonStrictTokens) } type downCaser struct { t *testing.T r io.ByteReader } func (d *downCaser) ReadByte() (c byte, err error) { c, err = d.r.ReadByte() if c >= 'A' && c <= 'Z' { c += 'a' - 'A' } return } func (d *downCaser) Read(p []byte) (int, error) { d.t.Fatalf("unexpected Read call on downCaser reader") panic("unreachable") } func TestRawTokenAltEncoding(t *testing.T) { d := NewDecoder(strings.NewReader(testInputAltEncoding)) d.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { if charset != "x-testing-uppercase" { t.Fatalf("unexpected charset %q", charset) } return &downCaser{t, input.(io.ByteReader)}, nil } testRawToken(t, d, testInputAltEncoding, rawTokensAltEncoding) } func TestRawTokenAltEncodingNoConverter(t *testing.T) { d := NewDecoder(strings.NewReader(testInputAltEncoding)) token, err := d.RawToken() if token == nil { t.Fatalf("expected a token on first RawToken call") } if err != nil { t.Fatal(err) } token, err = d.RawToken() if token != nil { t.Errorf("expected a nil token; got %#v", token) } if err == nil { t.Fatalf("expected an error on second RawToken call") } const encoding = "x-testing-uppercase" if !strings.Contains(err.Error(), encoding) { t.Errorf("expected error to contain %q; got error: %v", encoding, err) } } func testRawToken(t *testing.T, d *Decoder, raw string, rawTokens []Token) { lastEnd := int64(0) for i, want := range rawTokens { start := d.InputOffset() have, err := d.RawToken() end := d.InputOffset() if err != nil { t.Fatalf("token %d: unexpected error: %s", i, err) } if !reflect.DeepEqual(have, want) { var shave, swant string if _, ok := have.(CharData); ok { shave = fmt.Sprintf("CharData(%q)", have) } else { shave = fmt.Sprintf("%#v", have) } if _, ok := want.(CharData); ok { swant = fmt.Sprintf("CharData(%q)", want) } else { swant = fmt.Sprintf("%#v", want) } t.Errorf("token %d = %s, want %s", i, shave, swant) } // Check that InputOffset returned actual token. switch { case start < lastEnd: t.Errorf("token %d: position [%d,%d) for %T is before previous token", i, start, end, have) case start >= end: // Special case: EndElement can be synthesized. if start == end && end == lastEnd { break } t.Errorf("token %d: position [%d,%d) for %T is empty", i, start, end, have) case end > int64(len(raw)): t.Errorf("token %d: position [%d,%d) for %T extends beyond input", i, start, end, have) default: text := raw[start:end] if strings.ContainsAny(text, "<>") && (!strings.HasPrefix(text, "<") || !strings.HasSuffix(text, ">")) { t.Errorf("token %d: misaligned raw token %#q for %T", i, text, have) } } lastEnd = end } } // Ensure that directives (specifically !DOCTYPE) include the complete // text of any nested directives, noting that < and > do not change // nesting depth if they are in single or double quotes. var nestedDirectivesInput = ` ]> ">]> ]> '>]> ]> '>]> ]> ` var nestedDirectivesTokens = []Token{ CharData("\n"), Directive(`DOCTYPE []`), CharData("\n"), Directive(`DOCTYPE [">]`), CharData("\n"), Directive(`DOCTYPE []`), CharData("\n"), Directive(`DOCTYPE ['>]`), CharData("\n"), Directive(`DOCTYPE []`), CharData("\n"), Directive(`DOCTYPE ['>]`), CharData("\n"), Directive(`DOCTYPE []`), CharData("\n"), } func TestNestedDirectives(t *testing.T) { d := NewDecoder(strings.NewReader(nestedDirectivesInput)) for i, want := range nestedDirectivesTokens { have, err := d.Token() if err != nil { t.Fatalf("token %d: unexpected error: %s", i, err) } if !reflect.DeepEqual(have, want) { t.Errorf("token %d = %#v want %#v", i, have, want) } } } func TestToken(t *testing.T) { d := NewDecoder(strings.NewReader(testInput)) d.Entity = testEntity for i, want := range cookedTokens { have, err := d.Token() if err != nil { t.Fatalf("token %d: unexpected error: %s", i, err) } if !reflect.DeepEqual(have, want) { t.Errorf("token %d = %#v want %#v", i, have, want) } } } func TestSyntax(t *testing.T) { for i := range xmlInput { d := NewDecoder(strings.NewReader(xmlInput[i])) var err error for _, err = d.Token(); err == nil; _, err = d.Token() { } if _, ok := err.(*SyntaxError); !ok { t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i]) } } } type allScalars struct { True1 bool True2 bool False1 bool False2 bool Int int Int8 int8 Int16 int16 Int32 int32 Int64 int64 Uint int Uint8 uint8 Uint16 uint16 Uint32 uint32 Uint64 uint64 Uintptr uintptr Float32 float32 Float64 float64 String string PtrString *string } var all = allScalars{ True1: true, True2: true, False1: false, False2: false, Int: 1, Int8: -2, Int16: 3, Int32: -4, Int64: 5, Uint: 6, Uint8: 7, Uint16: 8, Uint32: 9, Uint64: 10, Uintptr: 11, Float32: 13.0, Float64: 14.0, String: "15", PtrString: &sixteen, } var sixteen = "16" const testScalarsInput = ` true 1 false 0 1 -2 3 -4 5 6 7 8 9 10 11 12.0 13.0 14.0 15 16 ` func TestAllScalars(t *testing.T) { var a allScalars err := Unmarshal([]byte(testScalarsInput), &a) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(a, all) { t.Errorf("have %+v want %+v", a, all) } } type item struct { Field_a string } func TestIssue569(t *testing.T) { data := `abcd` var i item err := Unmarshal([]byte(data), &i) if err != nil || i.Field_a != "abcd" { t.Fatal("Expecting abcd") } } func TestUnquotedAttrs(t *testing.T) { data := "" d := NewDecoder(strings.NewReader(data)) d.Strict = false token, err := d.Token() if _, ok := err.(*SyntaxError); ok { t.Errorf("Unexpected error: %v", err) } if token.(StartElement).Name.Local != "tag" { t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local) } attr := token.(StartElement).Attr[0] if attr.Value != "azAZ09:-_" { t.Errorf("Unexpected attribute value: %v", attr.Value) } if attr.Name.Local != "attr" { t.Errorf("Unexpected attribute name: %v", attr.Name.Local) } } func TestValuelessAttrs(t *testing.T) { tests := [][3]string{ {"

    ", "p", "nowrap"}, {"

    ", "p", "nowrap"}, {"", "input", "checked"}, {"", "input", "checked"}, } for _, test := range tests { d := NewDecoder(strings.NewReader(test[0])) d.Strict = false token, err := d.Token() if _, ok := err.(*SyntaxError); ok { t.Errorf("Unexpected error: %v", err) } if token.(StartElement).Name.Local != test[1] { t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local) } attr := token.(StartElement).Attr[0] if attr.Value != test[2] { t.Errorf("Unexpected attribute value: %v", attr.Value) } if attr.Name.Local != test[2] { t.Errorf("Unexpected attribute name: %v", attr.Name.Local) } } } func TestCopyTokenCharData(t *testing.T) { data := []byte("same data") var tok1 Token = CharData(data) tok2 := CopyToken(tok1) if !reflect.DeepEqual(tok1, tok2) { t.Error("CopyToken(CharData) != CharData") } data[1] = 'o' if reflect.DeepEqual(tok1, tok2) { t.Error("CopyToken(CharData) uses same buffer.") } } func TestCopyTokenStartElement(t *testing.T) { elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}} var tok1 Token = elt tok2 := CopyToken(tok1) if tok1.(StartElement).Attr[0].Value != "en" { t.Error("CopyToken overwrote Attr[0]") } if !reflect.DeepEqual(tok1, tok2) { t.Error("CopyToken(StartElement) != StartElement") } tok1.(StartElement).Attr[0] = Attr{Name{"", "lang"}, "de"} if reflect.DeepEqual(tok1, tok2) { t.Error("CopyToken(CharData) uses same buffer.") } } func TestSyntaxErrorLineNum(t *testing.T) { testInput := "

    Foo

    \n\n

    Bar\n" d := NewDecoder(strings.NewReader(testInput)) var err error for _, err = d.Token(); err == nil; _, err = d.Token() { } synerr, ok := err.(*SyntaxError) if !ok { t.Error("Expected SyntaxError.") } if synerr.Line != 3 { t.Error("SyntaxError didn't have correct line number.") } } func TestTrailingRawToken(t *testing.T) { input := ` ` d := NewDecoder(strings.NewReader(input)) var err error for _, err = d.RawToken(); err == nil; _, err = d.RawToken() { } if err != io.EOF { t.Fatalf("d.RawToken() = _, %v, want _, io.EOF", err) } } func TestTrailingToken(t *testing.T) { input := ` ` d := NewDecoder(strings.NewReader(input)) var err error for _, err = d.Token(); err == nil; _, err = d.Token() { } if err != io.EOF { t.Fatalf("d.Token() = _, %v, want _, io.EOF", err) } } func TestEntityInsideCDATA(t *testing.T) { input := `` d := NewDecoder(strings.NewReader(input)) var err error for _, err = d.Token(); err == nil; _, err = d.Token() { } if err != io.EOF { t.Fatalf("d.Token() = _, %v, want _, io.EOF", err) } } var characterTests = []struct { in string err string }{ {"\x12", "illegal character code U+0012"}, {"\x0b", "illegal character code U+000B"}, {"\xef\xbf\xbe", "illegal character code U+FFFE"}, {"\r\n\x07", "illegal character code U+0007"}, {"what's up", "expected attribute name in element"}, {"&abc\x01;", "invalid character entity &abc (no semicolon)"}, {"&\x01;", "invalid character entity & (no semicolon)"}, {"&\xef\xbf\xbe;", "invalid character entity &\uFFFE;"}, {"&hello;", "invalid character entity &hello;"}, } func TestDisallowedCharacters(t *testing.T) { for i, tt := range characterTests { d := NewDecoder(strings.NewReader(tt.in)) var err error for err == nil { _, err = d.Token() } synerr, ok := err.(*SyntaxError) if !ok { t.Fatalf("input %d d.Token() = _, %v, want _, *SyntaxError", i, err) } if synerr.Msg != tt.err { t.Fatalf("input %d synerr.Msg wrong: want %q, got %q", i, tt.err, synerr.Msg) } } } type procInstEncodingTest struct { expect, got string } var procInstTests = []struct { input string expect [2]string }{ {`version="1.0" encoding="utf-8"`, [2]string{"1.0", "utf-8"}}, {`version="1.0" encoding='utf-8'`, [2]string{"1.0", "utf-8"}}, {`version="1.0" encoding='utf-8' `, [2]string{"1.0", "utf-8"}}, {`version="1.0" encoding=utf-8`, [2]string{"1.0", ""}}, {`encoding="FOO" `, [2]string{"", "FOO"}}, } func TestProcInstEncoding(t *testing.T) { for _, test := range procInstTests { if got := procInst("version", test.input); got != test.expect[0] { t.Errorf("procInst(version, %q) = %q; want %q", test.input, got, test.expect[0]) } if got := procInst("encoding", test.input); got != test.expect[1] { t.Errorf("procInst(encoding, %q) = %q; want %q", test.input, got, test.expect[1]) } } } // Ensure that directives with comments include the complete // text of any nested directives. var directivesWithCommentsInput = ` ]> ]> --> --> []> ` var directivesWithCommentsTokens = []Token{ CharData("\n"), Directive(`DOCTYPE []`), CharData("\n"), Directive(`DOCTYPE []`), CharData("\n"), Directive(`DOCTYPE []`), CharData("\n"), } func TestDirectivesWithComments(t *testing.T) { d := NewDecoder(strings.NewReader(directivesWithCommentsInput)) for i, want := range directivesWithCommentsTokens { have, err := d.Token() if err != nil { t.Fatalf("token %d: unexpected error: %s", i, err) } if !reflect.DeepEqual(have, want) { t.Errorf("token %d = %#v want %#v", i, have, want) } } } // Writer whose Write method always returns an error. type errWriter struct{} func (errWriter) Write(p []byte) (n int, err error) { return 0, fmt.Errorf("unwritable") } func TestEscapeTextIOErrors(t *testing.T) { expectErr := "unwritable" err := EscapeText(errWriter{}, []byte{'A'}) if err == nil || err.Error() != expectErr { t.Errorf("have %v, want %v", err, expectErr) } } func TestEscapeTextInvalidChar(t *testing.T) { input := []byte("A \x00 terminated string.") expected := "A \uFFFD terminated string." buff := new(bytes.Buffer) if err := EscapeText(buff, input); err != nil { t.Fatalf("have %v, want nil", err) } text := buff.String() if text != expected { t.Errorf("have %v, want %v", text, expected) } } func TestIssue5880(t *testing.T) { type T []byte data, err := Marshal(T{192, 168, 0, 1}) if err != nil { t.Errorf("Marshal error: %v", err) } if !utf8.Valid(data) { t.Errorf("Marshal generated invalid UTF-8: %x", data) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/litmus_test_server.go000066400000000000000000000053451264464372400262100ustar00rootroot00000000000000// Copyright 2015 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. // +build ignore /* This program is a server for the WebDAV 'litmus' compliance test at http://www.webdav.org/neon/litmus/ To run the test: go run litmus_test_server.go and separately, from the downloaded litmus-xxx directory: make URL=http://localhost:9999/ check */ package main import ( "flag" "fmt" "log" "net/http" "net/url" "golang.org/x/net/webdav" ) var port = flag.Int("port", 9999, "server port") func main() { flag.Parse() log.SetFlags(0) h := &webdav.Handler{ FileSystem: webdav.NewMemFS(), LockSystem: webdav.NewMemLS(), Logger: func(r *http.Request, err error) { litmus := r.Header.Get("X-Litmus") if len(litmus) > 19 { litmus = litmus[:16] + "..." } switch r.Method { case "COPY", "MOVE": dst := "" if u, err := url.Parse(r.Header.Get("Destination")); err == nil { dst = u.Path } o := r.Header.Get("Overwrite") log.Printf("%-20s%-10s%-30s%-30so=%-2s%v", litmus, r.Method, r.URL.Path, dst, o, err) default: log.Printf("%-20s%-10s%-30s%v", litmus, r.Method, r.URL.Path, err) } }, } // The next line would normally be: // http.Handle("/", h) // but we wrap that HTTP handler h to cater for a special case. // // The propfind_invalid2 litmus test case expects an empty namespace prefix // declaration to be an error. The FAQ in the webdav litmus test says: // // "What does the "propfind_invalid2" test check for?... // // If a request was sent with an XML body which included an empty namespace // prefix declaration (xmlns:ns1=""), then the server must reject that with // a "400 Bad Request" response, as it is invalid according to the XML // Namespace specification." // // On the other hand, the Go standard library's encoding/xml package // accepts an empty xmlns namespace, as per the discussion at // https://github.com/golang/go/issues/8068 // // Empty namespaces seem disallowed in the second (2006) edition of the XML // standard, but allowed in a later edition. The grammar differs between // http://www.w3.org/TR/2006/REC-xml-names-20060816/#ns-decl and // http://www.w3.org/TR/REC-xml-names/#dt-prefix // // Thus, we assume that the propfind_invalid2 test is obsolete, and // hard-code the 400 Bad Request response that the test expects. http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("X-Litmus") == "props: 3 (propfind_invalid2)" { http.Error(w, "400 Bad Request", http.StatusBadRequest) return } h.ServeHTTP(w, r) })) addr := fmt.Sprintf(":%d", *port) log.Printf("Serving %v", addr) log.Fatal(http.ListenAndServe(addr, nil)) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/lock.go000066400000000000000000000275251264464372400232020ustar00rootroot00000000000000// Copyright 2014 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 webdav import ( "container/heap" "errors" "strconv" "strings" "sync" "time" ) var ( // ErrConfirmationFailed is returned by a LockSystem's Confirm method. ErrConfirmationFailed = errors.New("webdav: confirmation failed") // ErrForbidden is returned by a LockSystem's Unlock method. ErrForbidden = errors.New("webdav: forbidden") // ErrLocked is returned by a LockSystem's Create, Refresh and Unlock methods. ErrLocked = errors.New("webdav: locked") // ErrNoSuchLock is returned by a LockSystem's Refresh and Unlock methods. ErrNoSuchLock = errors.New("webdav: no such lock") ) // Condition can match a WebDAV resource, based on a token or ETag. // Exactly one of Token and ETag should be non-empty. type Condition struct { Not bool Token string ETag string } // LockSystem manages access to a collection of named resources. The elements // in a lock name are separated by slash ('/', U+002F) characters, regardless // of host operating system convention. type LockSystem interface { // Confirm confirms that the caller can claim all of the locks specified by // the given conditions, and that holding the union of all of those locks // gives exclusive access to all of the named resources. Up to two resources // can be named. Empty names are ignored. // // Exactly one of release and err will be non-nil. If release is non-nil, // all of the requested locks are held until release is called. Calling // release does not unlock the lock, in the WebDAV UNLOCK sense, but once // Confirm has confirmed that a lock claim is valid, that lock cannot be // Confirmed again until it has been released. // // If Confirm returns ErrConfirmationFailed then the Handler will continue // to try any other set of locks presented (a WebDAV HTTP request can // present more than one set of locks). If it returns any other non-nil // error, the Handler will write a "500 Internal Server Error" HTTP status. Confirm(now time.Time, name0, name1 string, conditions ...Condition) (release func(), err error) // Create creates a lock with the given depth, duration, owner and root // (name). The depth will either be negative (meaning infinite) or zero. // // If Create returns ErrLocked then the Handler will write a "423 Locked" // HTTP status. If it returns any other non-nil error, the Handler will // write a "500 Internal Server Error" HTTP status. // // See http://www.webdav.org/specs/rfc4918.html#rfc.section.9.10.6 for // when to use each error. // // The token returned identifies the created lock. It should be an absolute // URI as defined by RFC 3986, Section 4.3. In particular, it should not // contain whitespace. Create(now time.Time, details LockDetails) (token string, err error) // Refresh refreshes the lock with the given token. // // If Refresh returns ErrLocked then the Handler will write a "423 Locked" // HTTP Status. If Refresh returns ErrNoSuchLock then the Handler will write // a "412 Precondition Failed" HTTP Status. If it returns any other non-nil // error, the Handler will write a "500 Internal Server Error" HTTP status. // // See http://www.webdav.org/specs/rfc4918.html#rfc.section.9.10.6 for // when to use each error. Refresh(now time.Time, token string, duration time.Duration) (LockDetails, error) // Unlock unlocks the lock with the given token. // // If Unlock returns ErrForbidden then the Handler will write a "403 // Forbidden" HTTP Status. If Unlock returns ErrLocked then the Handler // will write a "423 Locked" HTTP status. If Unlock returns ErrNoSuchLock // then the Handler will write a "409 Conflict" HTTP Status. If it returns // any other non-nil error, the Handler will write a "500 Internal Server // Error" HTTP status. // // See http://www.webdav.org/specs/rfc4918.html#rfc.section.9.11.1 for // when to use each error. Unlock(now time.Time, token string) error } // LockDetails are a lock's metadata. type LockDetails struct { // Root is the root resource name being locked. For a zero-depth lock, the // root is the only resource being locked. Root string // Duration is the lock timeout. A negative duration means infinite. Duration time.Duration // OwnerXML is the verbatim XML given in a LOCK HTTP request. // // TODO: does the "verbatim" nature play well with XML namespaces? // Does the OwnerXML field need to have more structure? See // https://codereview.appspot.com/175140043/#msg2 OwnerXML string // ZeroDepth is whether the lock has zero depth. If it does not have zero // depth, it has infinite depth. ZeroDepth bool } // NewMemLS returns a new in-memory LockSystem. func NewMemLS() LockSystem { return &memLS{ byName: make(map[string]*memLSNode), byToken: make(map[string]*memLSNode), gen: uint64(time.Now().Unix()), } } type memLS struct { mu sync.Mutex byName map[string]*memLSNode byToken map[string]*memLSNode gen uint64 // byExpiry only contains those nodes whose LockDetails have a finite // Duration and are yet to expire. byExpiry byExpiry } func (m *memLS) nextToken() string { m.gen++ return strconv.FormatUint(m.gen, 10) } func (m *memLS) collectExpiredNodes(now time.Time) { for len(m.byExpiry) > 0 { if now.Before(m.byExpiry[0].expiry) { break } m.remove(m.byExpiry[0]) } } func (m *memLS) Confirm(now time.Time, name0, name1 string, conditions ...Condition) (func(), error) { m.mu.Lock() defer m.mu.Unlock() m.collectExpiredNodes(now) var n0, n1 *memLSNode if name0 != "" { if n0 = m.lookup(slashClean(name0), conditions...); n0 == nil { return nil, ErrConfirmationFailed } } if name1 != "" { if n1 = m.lookup(slashClean(name1), conditions...); n1 == nil { return nil, ErrConfirmationFailed } } // Don't hold the same node twice. if n1 == n0 { n1 = nil } if n0 != nil { m.hold(n0) } if n1 != nil { m.hold(n1) } return func() { m.mu.Lock() defer m.mu.Unlock() if n1 != nil { m.unhold(n1) } if n0 != nil { m.unhold(n0) } }, nil } // lookup returns the node n that locks the named resource, provided that n // matches at least one of the given conditions and that lock isn't held by // another party. Otherwise, it returns nil. // // n may be a parent of the named resource, if n is an infinite depth lock. func (m *memLS) lookup(name string, conditions ...Condition) (n *memLSNode) { // TODO: support Condition.Not and Condition.ETag. for _, c := range conditions { n = m.byToken[c.Token] if n == nil || n.held { continue } if name == n.details.Root { return n } if n.details.ZeroDepth { continue } if n.details.Root == "/" || strings.HasPrefix(name, n.details.Root+"/") { return n } } return nil } func (m *memLS) hold(n *memLSNode) { if n.held { panic("webdav: memLS inconsistent held state") } n.held = true if n.details.Duration >= 0 && n.byExpiryIndex >= 0 { heap.Remove(&m.byExpiry, n.byExpiryIndex) } } func (m *memLS) unhold(n *memLSNode) { if !n.held { panic("webdav: memLS inconsistent held state") } n.held = false if n.details.Duration >= 0 { heap.Push(&m.byExpiry, n) } } func (m *memLS) Create(now time.Time, details LockDetails) (string, error) { m.mu.Lock() defer m.mu.Unlock() m.collectExpiredNodes(now) details.Root = slashClean(details.Root) if !m.canCreate(details.Root, details.ZeroDepth) { return "", ErrLocked } n := m.create(details.Root) n.token = m.nextToken() m.byToken[n.token] = n n.details = details if n.details.Duration >= 0 { n.expiry = now.Add(n.details.Duration) heap.Push(&m.byExpiry, n) } return n.token, nil } func (m *memLS) Refresh(now time.Time, token string, duration time.Duration) (LockDetails, error) { m.mu.Lock() defer m.mu.Unlock() m.collectExpiredNodes(now) n := m.byToken[token] if n == nil { return LockDetails{}, ErrNoSuchLock } if n.held { return LockDetails{}, ErrLocked } if n.byExpiryIndex >= 0 { heap.Remove(&m.byExpiry, n.byExpiryIndex) } n.details.Duration = duration if n.details.Duration >= 0 { n.expiry = now.Add(n.details.Duration) heap.Push(&m.byExpiry, n) } return n.details, nil } func (m *memLS) Unlock(now time.Time, token string) error { m.mu.Lock() defer m.mu.Unlock() m.collectExpiredNodes(now) n := m.byToken[token] if n == nil { return ErrNoSuchLock } if n.held { return ErrLocked } m.remove(n) return nil } func (m *memLS) canCreate(name string, zeroDepth bool) bool { return walkToRoot(name, func(name0 string, first bool) bool { n := m.byName[name0] if n == nil { return true } if first { if n.token != "" { // The target node is already locked. return false } if !zeroDepth { // The requested lock depth is infinite, and the fact that n exists // (n != nil) means that a descendent of the target node is locked. return false } } else if n.token != "" && !n.details.ZeroDepth { // An ancestor of the target node is locked with infinite depth. return false } return true }) } func (m *memLS) create(name string) (ret *memLSNode) { walkToRoot(name, func(name0 string, first bool) bool { n := m.byName[name0] if n == nil { n = &memLSNode{ details: LockDetails{ Root: name0, }, byExpiryIndex: -1, } m.byName[name0] = n } n.refCount++ if first { ret = n } return true }) return ret } func (m *memLS) remove(n *memLSNode) { delete(m.byToken, n.token) n.token = "" walkToRoot(n.details.Root, func(name0 string, first bool) bool { x := m.byName[name0] x.refCount-- if x.refCount == 0 { delete(m.byName, name0) } return true }) if n.byExpiryIndex >= 0 { heap.Remove(&m.byExpiry, n.byExpiryIndex) } } func walkToRoot(name string, f func(name0 string, first bool) bool) bool { for first := true; ; first = false { if !f(name, first) { return false } if name == "/" { break } name = name[:strings.LastIndex(name, "/")] if name == "" { name = "/" } } return true } type memLSNode struct { // details are the lock metadata. Even if this node's name is not explicitly locked, // details.Root will still equal the node's name. details LockDetails // token is the unique identifier for this node's lock. An empty token means that // this node is not explicitly locked. token string // refCount is the number of self-or-descendent nodes that are explicitly locked. refCount int // expiry is when this node's lock expires. expiry time.Time // byExpiryIndex is the index of this node in memLS.byExpiry. It is -1 // if this node does not expire, or has expired. byExpiryIndex int // held is whether this node's lock is actively held by a Confirm call. held bool } type byExpiry []*memLSNode func (b *byExpiry) Len() int { return len(*b) } func (b *byExpiry) Less(i, j int) bool { return (*b)[i].expiry.Before((*b)[j].expiry) } func (b *byExpiry) Swap(i, j int) { (*b)[i], (*b)[j] = (*b)[j], (*b)[i] (*b)[i].byExpiryIndex = i (*b)[j].byExpiryIndex = j } func (b *byExpiry) Push(x interface{}) { n := x.(*memLSNode) n.byExpiryIndex = len(*b) *b = append(*b, n) } func (b *byExpiry) Pop() interface{} { i := len(*b) - 1 n := (*b)[i] (*b)[i] = nil n.byExpiryIndex = -1 *b = (*b)[:i] return n } const infiniteTimeout = -1 // parseTimeout parses the Timeout HTTP header, as per section 10.7. If s is // empty, an infiniteTimeout is returned. func parseTimeout(s string) (time.Duration, error) { if s == "" { return infiniteTimeout, nil } if i := strings.IndexByte(s, ','); i >= 0 { s = s[:i] } s = strings.TrimSpace(s) if s == "Infinite" { return infiniteTimeout, nil } const pre = "Second-" if !strings.HasPrefix(s, pre) { return 0, errInvalidTimeout } s = s[len(pre):] if s == "" || s[0] < '0' || '9' < s[0] { return 0, errInvalidTimeout } n, err := strconv.ParseInt(s, 10, 64) if err != nil || 1<<32-1 < n { return 0, errInvalidTimeout } return time.Duration(n) * time.Second, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/lock_test.go000066400000000000000000000432741264464372400242400ustar00rootroot00000000000000// Copyright 2014 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 webdav import ( "fmt" "math/rand" "path" "reflect" "sort" "strconv" "strings" "testing" "time" ) func TestWalkToRoot(t *testing.T) { testCases := []struct { name string want []string }{{ "/a/b/c/d", []string{ "/a/b/c/d", "/a/b/c", "/a/b", "/a", "/", }, }, { "/a", []string{ "/a", "/", }, }, { "/", []string{ "/", }, }} for _, tc := range testCases { var got []string if !walkToRoot(tc.name, func(name0 string, first bool) bool { if first != (len(got) == 0) { t.Errorf("name=%q: first=%t but len(got)==%d", tc.name, first, len(got)) return false } got = append(got, name0) return true }) { continue } if !reflect.DeepEqual(got, tc.want) { t.Errorf("name=%q:\ngot %q\nwant %q", tc.name, got, tc.want) } } } var lockTestDurations = []time.Duration{ infiniteTimeout, // infiniteTimeout means to never expire. 0, // A zero duration means to expire immediately. 100 * time.Hour, // A very large duration will not expire in these tests. } // lockTestNames are the names of a set of mutually compatible locks. For each // name fragment: // - _ means no explicit lock. // - i means a infinite-depth lock, // - z means a zero-depth lock, var lockTestNames = []string{ "/_/_/_/_/z", "/_/_/i", "/_/z", "/_/z/i", "/_/z/z", "/_/z/_/i", "/_/z/_/z", "/i", "/z", "/z/_/i", "/z/_/z", } func lockTestZeroDepth(name string) bool { switch name[len(name)-1] { case 'i': return false case 'z': return true } panic(fmt.Sprintf("lock name %q did not end with 'i' or 'z'", name)) } func TestMemLSCanCreate(t *testing.T) { now := time.Unix(0, 0) m := NewMemLS().(*memLS) for _, name := range lockTestNames { _, err := m.Create(now, LockDetails{ Root: name, Duration: infiniteTimeout, ZeroDepth: lockTestZeroDepth(name), }) if err != nil { t.Fatalf("creating lock for %q: %v", name, err) } } wantCanCreate := func(name string, zeroDepth bool) bool { for _, n := range lockTestNames { switch { case n == name: // An existing lock has the same name as the proposed lock. return false case strings.HasPrefix(n, name): // An existing lock would be a child of the proposed lock, // which conflicts if the proposed lock has infinite depth. if !zeroDepth { return false } case strings.HasPrefix(name, n): // An existing lock would be an ancestor of the proposed lock, // which conflicts if the ancestor has infinite depth. if n[len(n)-1] == 'i' { return false } } } return true } var check func(int, string) check = func(recursion int, name string) { for _, zeroDepth := range []bool{false, true} { got := m.canCreate(name, zeroDepth) want := wantCanCreate(name, zeroDepth) if got != want { t.Errorf("canCreate name=%q zeroDepth=%t: got %t, want %t", name, zeroDepth, got, want) } } if recursion == 6 { return } if name != "/" { name += "/" } for _, c := range "_iz" { check(recursion+1, name+string(c)) } } check(0, "/") } func TestMemLSLookup(t *testing.T) { now := time.Unix(0, 0) m := NewMemLS().(*memLS) badToken := m.nextToken() t.Logf("badToken=%q", badToken) for _, name := range lockTestNames { token, err := m.Create(now, LockDetails{ Root: name, Duration: infiniteTimeout, ZeroDepth: lockTestZeroDepth(name), }) if err != nil { t.Fatalf("creating lock for %q: %v", name, err) } t.Logf("%-15q -> node=%p token=%q", name, m.byName[name], token) } baseNames := append([]string{"/a", "/b/c"}, lockTestNames...) for _, baseName := range baseNames { for _, suffix := range []string{"", "/0", "/1/2/3"} { name := baseName + suffix goodToken := "" base := m.byName[baseName] if base != nil && (suffix == "" || !lockTestZeroDepth(baseName)) { goodToken = base.token } for _, token := range []string{badToken, goodToken} { if token == "" { continue } got := m.lookup(name, Condition{Token: token}) want := base if token == badToken { want = nil } if got != want { t.Errorf("name=%-20qtoken=%q (bad=%t): got %p, want %p", name, token, token == badToken, got, want) } } } } } func TestMemLSConfirm(t *testing.T) { now := time.Unix(0, 0) m := NewMemLS().(*memLS) alice, err := m.Create(now, LockDetails{ Root: "/alice", Duration: infiniteTimeout, ZeroDepth: false, }) tweedle, err := m.Create(now, LockDetails{ Root: "/tweedle", Duration: infiniteTimeout, ZeroDepth: false, }) if err != nil { t.Fatalf("Create: %v", err) } if err := m.consistent(); err != nil { t.Fatalf("Create: inconsistent state: %v", err) } // Test a mismatch between name and condition. _, err = m.Confirm(now, "/tweedle/dee", "", Condition{Token: alice}) if err != ErrConfirmationFailed { t.Fatalf("Confirm (mismatch): got %v, want ErrConfirmationFailed", err) } if err := m.consistent(); err != nil { t.Fatalf("Confirm (mismatch): inconsistent state: %v", err) } // Test two names (that fall under the same lock) in the one Confirm call. release, err := m.Confirm(now, "/tweedle/dee", "/tweedle/dum", Condition{Token: tweedle}) if err != nil { t.Fatalf("Confirm (twins): %v", err) } if err := m.consistent(); err != nil { t.Fatalf("Confirm (twins): inconsistent state: %v", err) } release() if err := m.consistent(); err != nil { t.Fatalf("release (twins): inconsistent state: %v", err) } // Test the same two names in overlapping Confirm / release calls. releaseDee, err := m.Confirm(now, "/tweedle/dee", "", Condition{Token: tweedle}) if err != nil { t.Fatalf("Confirm (sequence #0): %v", err) } if err := m.consistent(); err != nil { t.Fatalf("Confirm (sequence #0): inconsistent state: %v", err) } _, err = m.Confirm(now, "/tweedle/dum", "", Condition{Token: tweedle}) if err != ErrConfirmationFailed { t.Fatalf("Confirm (sequence #1): got %v, want ErrConfirmationFailed", err) } if err := m.consistent(); err != nil { t.Fatalf("Confirm (sequence #1): inconsistent state: %v", err) } releaseDee() if err := m.consistent(); err != nil { t.Fatalf("release (sequence #2): inconsistent state: %v", err) } releaseDum, err := m.Confirm(now, "/tweedle/dum", "", Condition{Token: tweedle}) if err != nil { t.Fatalf("Confirm (sequence #3): %v", err) } if err := m.consistent(); err != nil { t.Fatalf("Confirm (sequence #3): inconsistent state: %v", err) } // Test that you can't unlock a held lock. err = m.Unlock(now, tweedle) if err != ErrLocked { t.Fatalf("Unlock (sequence #4): got %v, want ErrLocked", err) } releaseDum() if err := m.consistent(); err != nil { t.Fatalf("release (sequence #5): inconsistent state: %v", err) } err = m.Unlock(now, tweedle) if err != nil { t.Fatalf("Unlock (sequence #6): %v", err) } if err := m.consistent(); err != nil { t.Fatalf("Unlock (sequence #6): inconsistent state: %v", err) } } func TestMemLSNonCanonicalRoot(t *testing.T) { now := time.Unix(0, 0) m := NewMemLS().(*memLS) token, err := m.Create(now, LockDetails{ Root: "/foo/./bar//", Duration: 1 * time.Second, }) if err != nil { t.Fatalf("Create: %v", err) } if err := m.consistent(); err != nil { t.Fatalf("Create: inconsistent state: %v", err) } if err := m.Unlock(now, token); err != nil { t.Fatalf("Unlock: %v", err) } if err := m.consistent(); err != nil { t.Fatalf("Unlock: inconsistent state: %v", err) } } func TestMemLSExpiry(t *testing.T) { m := NewMemLS().(*memLS) testCases := []string{ "setNow 0", "create /a.5", "want /a.5", "create /c.6", "want /a.5 /c.6", "create /a/b.7", "want /a.5 /a/b.7 /c.6", "setNow 4", "want /a.5 /a/b.7 /c.6", "setNow 5", "want /a/b.7 /c.6", "setNow 6", "want /a/b.7", "setNow 7", "want ", "setNow 8", "want ", "create /a.12", "create /b.13", "create /c.15", "create /a/d.16", "want /a.12 /a/d.16 /b.13 /c.15", "refresh /a.14", "want /a.14 /a/d.16 /b.13 /c.15", "setNow 12", "want /a.14 /a/d.16 /b.13 /c.15", "setNow 13", "want /a.14 /a/d.16 /c.15", "setNow 14", "want /a/d.16 /c.15", "refresh /a/d.20", "refresh /c.20", "want /a/d.20 /c.20", "setNow 20", "want ", } tokens := map[string]string{} zTime := time.Unix(0, 0) now := zTime for i, tc := range testCases { j := strings.IndexByte(tc, ' ') if j < 0 { t.Fatalf("test case #%d %q: invalid command", i, tc) } op, arg := tc[:j], tc[j+1:] switch op { default: t.Fatalf("test case #%d %q: invalid operation %q", i, tc, op) case "create", "refresh": parts := strings.Split(arg, ".") if len(parts) != 2 { t.Fatalf("test case #%d %q: invalid create", i, tc) } root := parts[0] d, err := strconv.Atoi(parts[1]) if err != nil { t.Fatalf("test case #%d %q: invalid duration", i, tc) } dur := time.Unix(0, 0).Add(time.Duration(d) * time.Second).Sub(now) switch op { case "create": token, err := m.Create(now, LockDetails{ Root: root, Duration: dur, ZeroDepth: true, }) if err != nil { t.Fatalf("test case #%d %q: Create: %v", i, tc, err) } tokens[root] = token case "refresh": token := tokens[root] if token == "" { t.Fatalf("test case #%d %q: no token for %q", i, tc, root) } got, err := m.Refresh(now, token, dur) if err != nil { t.Fatalf("test case #%d %q: Refresh: %v", i, tc, err) } want := LockDetails{ Root: root, Duration: dur, ZeroDepth: true, } if got != want { t.Fatalf("test case #%d %q:\ngot %v\nwant %v", i, tc, got, want) } } case "setNow": d, err := strconv.Atoi(arg) if err != nil { t.Fatalf("test case #%d %q: invalid duration", i, tc) } now = time.Unix(0, 0).Add(time.Duration(d) * time.Second) case "want": m.mu.Lock() m.collectExpiredNodes(now) got := make([]string, 0, len(m.byToken)) for _, n := range m.byToken { got = append(got, fmt.Sprintf("%s.%d", n.details.Root, n.expiry.Sub(zTime)/time.Second)) } m.mu.Unlock() sort.Strings(got) want := []string{} if arg != "" { want = strings.Split(arg, " ") } if !reflect.DeepEqual(got, want) { t.Fatalf("test case #%d %q:\ngot %q\nwant %q", i, tc, got, want) } } if err := m.consistent(); err != nil { t.Fatalf("test case #%d %q: inconsistent state: %v", i, tc, err) } } } func TestMemLS(t *testing.T) { now := time.Unix(0, 0) m := NewMemLS().(*memLS) rng := rand.New(rand.NewSource(0)) tokens := map[string]string{} nConfirm, nCreate, nRefresh, nUnlock := 0, 0, 0, 0 const N = 2000 for i := 0; i < N; i++ { name := lockTestNames[rng.Intn(len(lockTestNames))] duration := lockTestDurations[rng.Intn(len(lockTestDurations))] confirmed, unlocked := false, false // If the name was already locked, we randomly confirm/release, refresh // or unlock it. Otherwise, we create a lock. token := tokens[name] if token != "" { switch rng.Intn(3) { case 0: confirmed = true nConfirm++ release, err := m.Confirm(now, name, "", Condition{Token: token}) if err != nil { t.Fatalf("iteration #%d: Confirm %q: %v", i, name, err) } if err := m.consistent(); err != nil { t.Fatalf("iteration #%d: inconsistent state: %v", i, err) } release() case 1: nRefresh++ if _, err := m.Refresh(now, token, duration); err != nil { t.Fatalf("iteration #%d: Refresh %q: %v", i, name, err) } case 2: unlocked = true nUnlock++ if err := m.Unlock(now, token); err != nil { t.Fatalf("iteration #%d: Unlock %q: %v", i, name, err) } } } else { nCreate++ var err error token, err = m.Create(now, LockDetails{ Root: name, Duration: duration, ZeroDepth: lockTestZeroDepth(name), }) if err != nil { t.Fatalf("iteration #%d: Create %q: %v", i, name, err) } } if !confirmed { if duration == 0 || unlocked { // A zero-duration lock should expire immediately and is // effectively equivalent to being unlocked. tokens[name] = "" } else { tokens[name] = token } } if err := m.consistent(); err != nil { t.Fatalf("iteration #%d: inconsistent state: %v", i, err) } } if nConfirm < N/10 { t.Fatalf("too few Confirm calls: got %d, want >= %d", nConfirm, N/10) } if nCreate < N/10 { t.Fatalf("too few Create calls: got %d, want >= %d", nCreate, N/10) } if nRefresh < N/10 { t.Fatalf("too few Refresh calls: got %d, want >= %d", nRefresh, N/10) } if nUnlock < N/10 { t.Fatalf("too few Unlock calls: got %d, want >= %d", nUnlock, N/10) } } func (m *memLS) consistent() error { m.mu.Lock() defer m.mu.Unlock() // If m.byName is non-empty, then it must contain an entry for the root "/", // and its refCount should equal the number of locked nodes. if len(m.byName) > 0 { n := m.byName["/"] if n == nil { return fmt.Errorf(`non-empty m.byName does not contain the root "/"`) } if n.refCount != len(m.byToken) { return fmt.Errorf("root node refCount=%d, differs from len(m.byToken)=%d", n.refCount, len(m.byToken)) } } for name, n := range m.byName { // The map keys should be consistent with the node's copy of the key. if n.details.Root != name { return fmt.Errorf("node name %q != byName map key %q", n.details.Root, name) } // A name must be clean, and start with a "/". if len(name) == 0 || name[0] != '/' { return fmt.Errorf(`node name %q does not start with "/"`, name) } if name != path.Clean(name) { return fmt.Errorf(`node name %q is not clean`, name) } // A node's refCount should be positive. if n.refCount <= 0 { return fmt.Errorf("non-positive refCount for node at name %q", name) } // A node's refCount should be the number of self-or-descendents that // are locked (i.e. have a non-empty token). var list []string for name0, n0 := range m.byName { // All of lockTestNames' name fragments are one byte long: '_', 'i' or 'z', // so strings.HasPrefix is equivalent to self-or-descendent name match. // We don't have to worry about "/foo/bar" being a false positive match // for "/foo/b". if strings.HasPrefix(name0, name) && n0.token != "" { list = append(list, name0) } } if n.refCount != len(list) { sort.Strings(list) return fmt.Errorf("node at name %q has refCount %d but locked self-or-descendents are %q (len=%d)", name, n.refCount, list, len(list)) } // A node n is in m.byToken if it has a non-empty token. if n.token != "" { if _, ok := m.byToken[n.token]; !ok { return fmt.Errorf("node at name %q has token %q but not in m.byToken", name, n.token) } } // A node n is in m.byExpiry if it has a non-negative byExpiryIndex. if n.byExpiryIndex >= 0 { if n.byExpiryIndex >= len(m.byExpiry) { return fmt.Errorf("node at name %q has byExpiryIndex %d but m.byExpiry has length %d", name, n.byExpiryIndex, len(m.byExpiry)) } if n != m.byExpiry[n.byExpiryIndex] { return fmt.Errorf("node at name %q has byExpiryIndex %d but that indexes a different node", name, n.byExpiryIndex) } } } for token, n := range m.byToken { // The map keys should be consistent with the node's copy of the key. if n.token != token { return fmt.Errorf("node token %q != byToken map key %q", n.token, token) } // Every node in m.byToken is in m.byName. if _, ok := m.byName[n.details.Root]; !ok { return fmt.Errorf("node at name %q in m.byToken but not in m.byName", n.details.Root) } } for i, n := range m.byExpiry { // The slice indices should be consistent with the node's copy of the index. if n.byExpiryIndex != i { return fmt.Errorf("node byExpiryIndex %d != byExpiry slice index %d", n.byExpiryIndex, i) } // Every node in m.byExpiry is in m.byName. if _, ok := m.byName[n.details.Root]; !ok { return fmt.Errorf("node at name %q in m.byExpiry but not in m.byName", n.details.Root) } // No node in m.byExpiry should be held. if n.held { return fmt.Errorf("node at name %q in m.byExpiry is held", n.details.Root) } } return nil } func TestParseTimeout(t *testing.T) { testCases := []struct { s string want time.Duration wantErr error }{{ "", infiniteTimeout, nil, }, { "Infinite", infiniteTimeout, nil, }, { "Infinitesimal", 0, errInvalidTimeout, }, { "infinite", 0, errInvalidTimeout, }, { "Second-0", 0 * time.Second, nil, }, { "Second-123", 123 * time.Second, nil, }, { " Second-456 ", 456 * time.Second, nil, }, { "Second-4100000000", 4100000000 * time.Second, nil, }, { "junk", 0, errInvalidTimeout, }, { "Second-", 0, errInvalidTimeout, }, { "Second--1", 0, errInvalidTimeout, }, { "Second--123", 0, errInvalidTimeout, }, { "Second-+123", 0, errInvalidTimeout, }, { "Second-0x123", 0, errInvalidTimeout, }, { "second-123", 0, errInvalidTimeout, }, { "Second-4294967295", 4294967295 * time.Second, nil, }, { // Section 10.7 says that "The timeout value for TimeType "Second" // must not be greater than 2^32-1." "Second-4294967296", 0, errInvalidTimeout, }, { // This test case comes from section 9.10.9 of the spec. It says, // // "In this request, the client has specified that it desires an // infinite-length lock, if available, otherwise a timeout of 4.1 // billion seconds, if available." // // The Go WebDAV package always supports infinite length locks, // and ignores the fallback after the comma. "Infinite, Second-4100000000", infiniteTimeout, nil, }} for _, tc := range testCases { got, gotErr := parseTimeout(tc.s) if got != tc.want || gotErr != tc.wantErr { t.Errorf("parsing %q:\ngot %v, %v\nwant %v, %v", tc.s, got, gotErr, tc.want, tc.wantErr) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/prop.go000066400000000000000000000274231264464372400232270ustar00rootroot00000000000000// Copyright 2015 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 webdav import ( "fmt" "io" "mime" "net/http" "os" "path/filepath" "strconv" "golang.org/x/net/webdav/internal/xml" ) // Proppatch describes a property update instruction as defined in RFC 4918. // See http://www.webdav.org/specs/rfc4918.html#METHOD_PROPPATCH type Proppatch struct { // Remove specifies whether this patch removes properties. If it does not // remove them, it sets them. Remove bool // Props contains the properties to be set or removed. Props []Property } // Propstat describes a XML propstat element as defined in RFC 4918. // See http://www.webdav.org/specs/rfc4918.html#ELEMENT_propstat type Propstat struct { // Props contains the properties for which Status applies. Props []Property // Status defines the HTTP status code of the properties in Prop. // Allowed values include, but are not limited to the WebDAV status // code extensions for HTTP/1.1. // http://www.webdav.org/specs/rfc4918.html#status.code.extensions.to.http11 Status int // XMLError contains the XML representation of the optional error element. // XML content within this field must not rely on any predefined // namespace declarations or prefixes. If empty, the XML error element // is omitted. XMLError string // ResponseDescription contains the contents of the optional // responsedescription field. If empty, the XML element is omitted. ResponseDescription string } // makePropstats returns a slice containing those of x and y whose Props slice // is non-empty. If both are empty, it returns a slice containing an otherwise // zero Propstat whose HTTP status code is 200 OK. func makePropstats(x, y Propstat) []Propstat { pstats := make([]Propstat, 0, 2) if len(x.Props) != 0 { pstats = append(pstats, x) } if len(y.Props) != 0 { pstats = append(pstats, y) } if len(pstats) == 0 { pstats = append(pstats, Propstat{ Status: http.StatusOK, }) } return pstats } // DeadPropsHolder holds the dead properties of a resource. // // Dead properties are those properties that are explicitly defined. In // comparison, live properties, such as DAV:getcontentlength, are implicitly // defined by the underlying resource, and cannot be explicitly overridden or // removed. See the Terminology section of // http://www.webdav.org/specs/rfc4918.html#rfc.section.3 // // There is a whitelist of the names of live properties. This package handles // all live properties, and will only pass non-whitelisted names to the Patch // method of DeadPropsHolder implementations. type DeadPropsHolder interface { // DeadProps returns a copy of the dead properties held. DeadProps() (map[xml.Name]Property, error) // Patch patches the dead properties held. // // Patching is atomic; either all or no patches succeed. It returns (nil, // non-nil) if an internal server error occurred, otherwise the Propstats // collectively contain one Property for each proposed patch Property. If // all patches succeed, Patch returns a slice of length one and a Propstat // element with a 200 OK HTTP status code. If none succeed, for reasons // other than an internal server error, no Propstat has status 200 OK. // // For more details on when various HTTP status codes apply, see // http://www.webdav.org/specs/rfc4918.html#PROPPATCH-status Patch([]Proppatch) ([]Propstat, error) } // liveProps contains all supported, protected DAV: properties. var liveProps = map[xml.Name]struct { // findFn implements the propfind function of this property. If nil, // it indicates a hidden property. findFn func(FileSystem, LockSystem, string, os.FileInfo) (string, error) // dir is true if the property applies to directories. dir bool }{ xml.Name{Space: "DAV:", Local: "resourcetype"}: { findFn: findResourceType, dir: true, }, xml.Name{Space: "DAV:", Local: "displayname"}: { findFn: findDisplayName, dir: true, }, xml.Name{Space: "DAV:", Local: "getcontentlength"}: { findFn: findContentLength, dir: false, }, xml.Name{Space: "DAV:", Local: "getlastmodified"}: { findFn: findLastModified, dir: false, }, xml.Name{Space: "DAV:", Local: "creationdate"}: { findFn: nil, dir: false, }, xml.Name{Space: "DAV:", Local: "getcontentlanguage"}: { findFn: nil, dir: false, }, xml.Name{Space: "DAV:", Local: "getcontenttype"}: { findFn: findContentType, dir: false, }, xml.Name{Space: "DAV:", Local: "getetag"}: { findFn: findETag, // findETag implements ETag as the concatenated hex values of a file's // modification time and size. This is not a reliable synchronization // mechanism for directories, so we do not advertise getetag for DAV // collections. dir: false, }, // TODO: The lockdiscovery property requires LockSystem to list the // active locks on a resource. xml.Name{Space: "DAV:", Local: "lockdiscovery"}: {}, xml.Name{Space: "DAV:", Local: "supportedlock"}: { findFn: findSupportedLock, dir: true, }, } // TODO(nigeltao) merge props and allprop? // Props returns the status of the properties named pnames for resource name. // // Each Propstat has a unique status and each property name will only be part // of one Propstat element. func props(fs FileSystem, ls LockSystem, name string, pnames []xml.Name) ([]Propstat, error) { f, err := fs.OpenFile(name, os.O_RDONLY, 0) if err != nil { return nil, err } defer f.Close() fi, err := f.Stat() if err != nil { return nil, err } isDir := fi.IsDir() var deadProps map[xml.Name]Property if dph, ok := f.(DeadPropsHolder); ok { deadProps, err = dph.DeadProps() if err != nil { return nil, err } } pstatOK := Propstat{Status: http.StatusOK} pstatNotFound := Propstat{Status: http.StatusNotFound} for _, pn := range pnames { // If this file has dead properties, check if they contain pn. if dp, ok := deadProps[pn]; ok { pstatOK.Props = append(pstatOK.Props, dp) continue } // Otherwise, it must either be a live property or we don't know it. if prop := liveProps[pn]; prop.findFn != nil && (prop.dir || !isDir) { innerXML, err := prop.findFn(fs, ls, name, fi) if err != nil { return nil, err } pstatOK.Props = append(pstatOK.Props, Property{ XMLName: pn, InnerXML: []byte(innerXML), }) } else { pstatNotFound.Props = append(pstatNotFound.Props, Property{ XMLName: pn, }) } } return makePropstats(pstatOK, pstatNotFound), nil } // Propnames returns the property names defined for resource name. func propnames(fs FileSystem, ls LockSystem, name string) ([]xml.Name, error) { f, err := fs.OpenFile(name, os.O_RDONLY, 0) if err != nil { return nil, err } defer f.Close() fi, err := f.Stat() if err != nil { return nil, err } isDir := fi.IsDir() var deadProps map[xml.Name]Property if dph, ok := f.(DeadPropsHolder); ok { deadProps, err = dph.DeadProps() if err != nil { return nil, err } } pnames := make([]xml.Name, 0, len(liveProps)+len(deadProps)) for pn, prop := range liveProps { if prop.findFn != nil && (prop.dir || !isDir) { pnames = append(pnames, pn) } } for pn := range deadProps { pnames = append(pnames, pn) } return pnames, nil } // Allprop returns the properties defined for resource name and the properties // named in include. // // Note that RFC 4918 defines 'allprop' to return the DAV: properties defined // within the RFC plus dead properties. Other live properties should only be // returned if they are named in 'include'. // // See http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND func allprop(fs FileSystem, ls LockSystem, name string, include []xml.Name) ([]Propstat, error) { pnames, err := propnames(fs, ls, name) if err != nil { return nil, err } // Add names from include if they are not already covered in pnames. nameset := make(map[xml.Name]bool) for _, pn := range pnames { nameset[pn] = true } for _, pn := range include { if !nameset[pn] { pnames = append(pnames, pn) } } return props(fs, ls, name, pnames) } // Patch patches the properties of resource name. The return values are // constrained in the same manner as DeadPropsHolder.Patch. func patch(fs FileSystem, ls LockSystem, name string, patches []Proppatch) ([]Propstat, error) { conflict := false loop: for _, patch := range patches { for _, p := range patch.Props { if _, ok := liveProps[p.XMLName]; ok { conflict = true break loop } } } if conflict { pstatForbidden := Propstat{ Status: http.StatusForbidden, XMLError: ``, } pstatFailedDep := Propstat{ Status: StatusFailedDependency, } for _, patch := range patches { for _, p := range patch.Props { if _, ok := liveProps[p.XMLName]; ok { pstatForbidden.Props = append(pstatForbidden.Props, Property{XMLName: p.XMLName}) } else { pstatFailedDep.Props = append(pstatFailedDep.Props, Property{XMLName: p.XMLName}) } } } return makePropstats(pstatForbidden, pstatFailedDep), nil } f, err := fs.OpenFile(name, os.O_RDWR, 0) if err != nil { return nil, err } defer f.Close() if dph, ok := f.(DeadPropsHolder); ok { ret, err := dph.Patch(patches) if err != nil { return nil, err } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_propstat says that // "The contents of the prop XML element must only list the names of // properties to which the result in the status element applies." for _, pstat := range ret { for i, p := range pstat.Props { pstat.Props[i] = Property{XMLName: p.XMLName} } } return ret, nil } // The file doesn't implement the optional DeadPropsHolder interface, so // all patches are forbidden. pstat := Propstat{Status: http.StatusForbidden} for _, patch := range patches { for _, p := range patch.Props { pstat.Props = append(pstat.Props, Property{XMLName: p.XMLName}) } } return []Propstat{pstat}, nil } func findResourceType(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) { if fi.IsDir() { return ``, nil } return "", nil } func findDisplayName(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) { if slashClean(name) == "/" { // Hide the real name of a possibly prefixed root directory. return "", nil } return fi.Name(), nil } func findContentLength(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) { return strconv.FormatInt(fi.Size(), 10), nil } func findLastModified(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) { return fi.ModTime().Format(http.TimeFormat), nil } func findContentType(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) { f, err := fs.OpenFile(name, os.O_RDONLY, 0) if err != nil { return "", err } defer f.Close() // This implementation is based on serveContent's code in the standard net/http package. ctype := mime.TypeByExtension(filepath.Ext(name)) if ctype != "" { return ctype, nil } // Read a chunk to decide between utf-8 text and binary. var buf [512]byte n, err := io.ReadFull(f, buf[:]) if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { return "", err } ctype = http.DetectContentType(buf[:n]) // Rewind file. _, err = f.Seek(0, os.SEEK_SET) return ctype, err } func findETag(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) { // The Apache http 2.4 web server by default concatenates the // modification time and size of a file. We replicate the heuristic // with nanosecond granularity. return fmt.Sprintf(`"%x%x"`, fi.ModTime().UnixNano(), fi.Size()), nil } func findSupportedLock(fs FileSystem, ls LockSystem, name string, fi os.FileInfo) (string, error) { return `` + `` + `` + `` + ``, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/prop_test.go000066400000000000000000000406051264464372400242630ustar00rootroot00000000000000// Copyright 2015 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 webdav import ( "fmt" "net/http" "os" "reflect" "sort" "testing" "golang.org/x/net/webdav/internal/xml" ) func TestMemPS(t *testing.T) { // calcProps calculates the getlastmodified and getetag DAV: property // values in pstats for resource name in file-system fs. calcProps := func(name string, fs FileSystem, ls LockSystem, pstats []Propstat) error { fi, err := fs.Stat(name) if err != nil { return err } for _, pst := range pstats { for i, p := range pst.Props { switch p.XMLName { case xml.Name{Space: "DAV:", Local: "getlastmodified"}: p.InnerXML = []byte(fi.ModTime().Format(http.TimeFormat)) pst.Props[i] = p case xml.Name{Space: "DAV:", Local: "getetag"}: if fi.IsDir() { continue } etag, err := findETag(fs, ls, name, fi) if err != nil { return err } p.InnerXML = []byte(etag) pst.Props[i] = p } } } return nil } const ( lockEntry = `` + `` + `` + `` + `` statForbiddenError = `` ) type propOp struct { op string name string pnames []xml.Name patches []Proppatch wantPnames []xml.Name wantPropstats []Propstat } testCases := []struct { desc string noDeadProps bool buildfs []string propOp []propOp }{{ desc: "propname", buildfs: []string{"mkdir /dir", "touch /file"}, propOp: []propOp{{ op: "propname", name: "/dir", wantPnames: []xml.Name{ xml.Name{Space: "DAV:", Local: "resourcetype"}, xml.Name{Space: "DAV:", Local: "displayname"}, xml.Name{Space: "DAV:", Local: "supportedlock"}, }, }, { op: "propname", name: "/file", wantPnames: []xml.Name{ xml.Name{Space: "DAV:", Local: "resourcetype"}, xml.Name{Space: "DAV:", Local: "displayname"}, xml.Name{Space: "DAV:", Local: "getcontentlength"}, xml.Name{Space: "DAV:", Local: "getlastmodified"}, xml.Name{Space: "DAV:", Local: "getcontenttype"}, xml.Name{Space: "DAV:", Local: "getetag"}, xml.Name{Space: "DAV:", Local: "supportedlock"}, }, }}, }, { desc: "allprop dir and file", buildfs: []string{"mkdir /dir", "write /file foobarbaz"}, propOp: []propOp{{ op: "allprop", name: "/dir", wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "resourcetype"}, InnerXML: []byte(``), }, { XMLName: xml.Name{Space: "DAV:", Local: "displayname"}, InnerXML: []byte("dir"), }, { XMLName: xml.Name{Space: "DAV:", Local: "supportedlock"}, InnerXML: []byte(lockEntry), }}, }}, }, { op: "allprop", name: "/file", wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "resourcetype"}, InnerXML: []byte(""), }, { XMLName: xml.Name{Space: "DAV:", Local: "displayname"}, InnerXML: []byte("file"), }, { XMLName: xml.Name{Space: "DAV:", Local: "getcontentlength"}, InnerXML: []byte("9"), }, { XMLName: xml.Name{Space: "DAV:", Local: "getlastmodified"}, InnerXML: nil, // Calculated during test. }, { XMLName: xml.Name{Space: "DAV:", Local: "getcontenttype"}, InnerXML: []byte("text/plain; charset=utf-8"), }, { XMLName: xml.Name{Space: "DAV:", Local: "getetag"}, InnerXML: nil, // Calculated during test. }, { XMLName: xml.Name{Space: "DAV:", Local: "supportedlock"}, InnerXML: []byte(lockEntry), }}, }}, }, { op: "allprop", name: "/file", pnames: []xml.Name{ {"DAV:", "resourcetype"}, {"foo", "bar"}, }, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "resourcetype"}, InnerXML: []byte(""), }, { XMLName: xml.Name{Space: "DAV:", Local: "displayname"}, InnerXML: []byte("file"), }, { XMLName: xml.Name{Space: "DAV:", Local: "getcontentlength"}, InnerXML: []byte("9"), }, { XMLName: xml.Name{Space: "DAV:", Local: "getlastmodified"}, InnerXML: nil, // Calculated during test. }, { XMLName: xml.Name{Space: "DAV:", Local: "getcontenttype"}, InnerXML: []byte("text/plain; charset=utf-8"), }, { XMLName: xml.Name{Space: "DAV:", Local: "getetag"}, InnerXML: nil, // Calculated during test. }, { XMLName: xml.Name{Space: "DAV:", Local: "supportedlock"}, InnerXML: []byte(lockEntry), }}}, { Status: http.StatusNotFound, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}}, }, }}, }, { desc: "propfind DAV:resourcetype", buildfs: []string{"mkdir /dir", "touch /file"}, propOp: []propOp{{ op: "propfind", name: "/dir", pnames: []xml.Name{{"DAV:", "resourcetype"}}, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "resourcetype"}, InnerXML: []byte(``), }}, }}, }, { op: "propfind", name: "/file", pnames: []xml.Name{{"DAV:", "resourcetype"}}, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "resourcetype"}, InnerXML: []byte(""), }}, }}, }}, }, { desc: "propfind unsupported DAV properties", buildfs: []string{"mkdir /dir"}, propOp: []propOp{{ op: "propfind", name: "/dir", pnames: []xml.Name{{"DAV:", "getcontentlanguage"}}, wantPropstats: []Propstat{{ Status: http.StatusNotFound, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "getcontentlanguage"}, }}, }}, }, { op: "propfind", name: "/dir", pnames: []xml.Name{{"DAV:", "creationdate"}}, wantPropstats: []Propstat{{ Status: http.StatusNotFound, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "creationdate"}, }}, }}, }}, }, { desc: "propfind getetag for files but not for directories", buildfs: []string{"mkdir /dir", "touch /file"}, propOp: []propOp{{ op: "propfind", name: "/dir", pnames: []xml.Name{{"DAV:", "getetag"}}, wantPropstats: []Propstat{{ Status: http.StatusNotFound, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "getetag"}, }}, }}, }, { op: "propfind", name: "/file", pnames: []xml.Name{{"DAV:", "getetag"}}, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "getetag"}, InnerXML: nil, // Calculated during test. }}, }}, }}, }, { desc: "proppatch property on no-dead-properties file system", buildfs: []string{"mkdir /dir"}, noDeadProps: true, propOp: []propOp{{ op: "proppatch", name: "/dir", patches: []Proppatch{{ Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }}, wantPropstats: []Propstat{{ Status: http.StatusForbidden, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }}, }, { op: "proppatch", name: "/dir", patches: []Proppatch{{ Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "getetag"}, }}, }}, wantPropstats: []Propstat{{ Status: http.StatusForbidden, XMLError: statForbiddenError, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "getetag"}, }}, }}, }}, }, { desc: "proppatch dead property", buildfs: []string{"mkdir /dir"}, propOp: []propOp{{ op: "proppatch", name: "/dir", patches: []Proppatch{{ Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, InnerXML: []byte("baz"), }}, }}, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }}, }, { op: "propfind", name: "/dir", pnames: []xml.Name{{Space: "foo", Local: "bar"}}, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, InnerXML: []byte("baz"), }}, }}, }}, }, { desc: "proppatch dead property with failed dependency", buildfs: []string{"mkdir /dir"}, propOp: []propOp{{ op: "proppatch", name: "/dir", patches: []Proppatch{{ Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, InnerXML: []byte("baz"), }}, }, { Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "displayname"}, InnerXML: []byte("xxx"), }}, }}, wantPropstats: []Propstat{{ Status: http.StatusForbidden, XMLError: statForbiddenError, Props: []Property{{ XMLName: xml.Name{Space: "DAV:", Local: "displayname"}, }}, }, { Status: StatusFailedDependency, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }}, }, { op: "propfind", name: "/dir", pnames: []xml.Name{{Space: "foo", Local: "bar"}}, wantPropstats: []Propstat{{ Status: http.StatusNotFound, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }}, }}, }, { desc: "proppatch remove dead property", buildfs: []string{"mkdir /dir"}, propOp: []propOp{{ op: "proppatch", name: "/dir", patches: []Proppatch{{ Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, InnerXML: []byte("baz"), }, { XMLName: xml.Name{Space: "spam", Local: "ham"}, InnerXML: []byte("eggs"), }}, }}, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }, { XMLName: xml.Name{Space: "spam", Local: "ham"}, }}, }}, }, { op: "propfind", name: "/dir", pnames: []xml.Name{ {Space: "foo", Local: "bar"}, {Space: "spam", Local: "ham"}, }, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, InnerXML: []byte("baz"), }, { XMLName: xml.Name{Space: "spam", Local: "ham"}, InnerXML: []byte("eggs"), }}, }}, }, { op: "proppatch", name: "/dir", patches: []Proppatch{{ Remove: true, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }}, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }}, }, { op: "propfind", name: "/dir", pnames: []xml.Name{ {Space: "foo", Local: "bar"}, {Space: "spam", Local: "ham"}, }, wantPropstats: []Propstat{{ Status: http.StatusNotFound, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }, { Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "spam", Local: "ham"}, InnerXML: []byte("eggs"), }}, }}, }}, }, { desc: "propname with dead property", buildfs: []string{"touch /file"}, propOp: []propOp{{ op: "proppatch", name: "/file", patches: []Proppatch{{ Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, InnerXML: []byte("baz"), }}, }}, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }}, }, { op: "propname", name: "/file", wantPnames: []xml.Name{ xml.Name{Space: "DAV:", Local: "resourcetype"}, xml.Name{Space: "DAV:", Local: "displayname"}, xml.Name{Space: "DAV:", Local: "getcontentlength"}, xml.Name{Space: "DAV:", Local: "getlastmodified"}, xml.Name{Space: "DAV:", Local: "getcontenttype"}, xml.Name{Space: "DAV:", Local: "getetag"}, xml.Name{Space: "DAV:", Local: "supportedlock"}, xml.Name{Space: "foo", Local: "bar"}, }, }}, }, { desc: "proppatch remove unknown dead property", buildfs: []string{"mkdir /dir"}, propOp: []propOp{{ op: "proppatch", name: "/dir", patches: []Proppatch{{ Remove: true, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }}, wantPropstats: []Propstat{{ Status: http.StatusOK, Props: []Property{{ XMLName: xml.Name{Space: "foo", Local: "bar"}, }}, }}, }}, }, { desc: "bad: propfind unknown property", buildfs: []string{"mkdir /dir"}, propOp: []propOp{{ op: "propfind", name: "/dir", pnames: []xml.Name{{"foo:", "bar"}}, wantPropstats: []Propstat{{ Status: http.StatusNotFound, Props: []Property{{ XMLName: xml.Name{Space: "foo:", Local: "bar"}, }}, }}, }}, }} for _, tc := range testCases { fs, err := buildTestFS(tc.buildfs) if err != nil { t.Fatalf("%s: cannot create test filesystem: %v", tc.desc, err) } if tc.noDeadProps { fs = noDeadPropsFS{fs} } ls := NewMemLS() for _, op := range tc.propOp { desc := fmt.Sprintf("%s: %s %s", tc.desc, op.op, op.name) if err = calcProps(op.name, fs, ls, op.wantPropstats); err != nil { t.Fatalf("%s: calcProps: %v", desc, err) } // Call property system. var propstats []Propstat switch op.op { case "propname": pnames, err := propnames(fs, ls, op.name) if err != nil { t.Errorf("%s: got error %v, want nil", desc, err) continue } sort.Sort(byXMLName(pnames)) sort.Sort(byXMLName(op.wantPnames)) if !reflect.DeepEqual(pnames, op.wantPnames) { t.Errorf("%s: pnames\ngot %q\nwant %q", desc, pnames, op.wantPnames) } continue case "allprop": propstats, err = allprop(fs, ls, op.name, op.pnames) case "propfind": propstats, err = props(fs, ls, op.name, op.pnames) case "proppatch": propstats, err = patch(fs, ls, op.name, op.patches) default: t.Fatalf("%s: %s not implemented", desc, op.op) } if err != nil { t.Errorf("%s: got error %v, want nil", desc, err) continue } // Compare return values from allprop, propfind or proppatch. for _, pst := range propstats { sort.Sort(byPropname(pst.Props)) } for _, pst := range op.wantPropstats { sort.Sort(byPropname(pst.Props)) } sort.Sort(byStatus(propstats)) sort.Sort(byStatus(op.wantPropstats)) if !reflect.DeepEqual(propstats, op.wantPropstats) { t.Errorf("%s: propstat\ngot %q\nwant %q", desc, propstats, op.wantPropstats) } } } } func cmpXMLName(a, b xml.Name) bool { if a.Space != b.Space { return a.Space < b.Space } return a.Local < b.Local } type byXMLName []xml.Name func (b byXMLName) Len() int { return len(b) } func (b byXMLName) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b byXMLName) Less(i, j int) bool { return cmpXMLName(b[i], b[j]) } type byPropname []Property func (b byPropname) Len() int { return len(b) } func (b byPropname) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b byPropname) Less(i, j int) bool { return cmpXMLName(b[i].XMLName, b[j].XMLName) } type byStatus []Propstat func (b byStatus) Len() int { return len(b) } func (b byStatus) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b byStatus) Less(i, j int) bool { return b[i].Status < b[j].Status } type noDeadPropsFS struct { FileSystem } func (fs noDeadPropsFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) { f, err := fs.FileSystem.OpenFile(name, flag, perm) if err != nil { return nil, err } return noDeadPropsFile{f}, nil } // noDeadPropsFile wraps a File but strips any optional DeadPropsHolder methods // provided by the underlying File implementation. type noDeadPropsFile struct { f File } func (f noDeadPropsFile) Close() error { return f.f.Close() } func (f noDeadPropsFile) Read(p []byte) (int, error) { return f.f.Read(p) } func (f noDeadPropsFile) Readdir(count int) ([]os.FileInfo, error) { return f.f.Readdir(count) } func (f noDeadPropsFile) Seek(off int64, whence int) (int64, error) { return f.f.Seek(off, whence) } func (f noDeadPropsFile) Stat() (os.FileInfo, error) { return f.f.Stat() } func (f noDeadPropsFile) Write(p []byte) (int, error) { return f.f.Write(p) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/webdav.go000066400000000000000000000511121264464372400235070ustar00rootroot00000000000000// Copyright 2014 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 webdav etc etc TODO. package webdav // import "golang.org/x/net/webdav" import ( "errors" "fmt" "io" "log" "net/http" "net/url" "os" "path" "runtime" "strings" "time" ) // Package webdav's XML output requires the standard library's encoding/xml // package version 1.5 or greater. Otherwise, it will produce malformed XML. // // As of May 2015, the Go stable release is version 1.4, so we print a message // to let users know that this golang.org/x/etc package won't work yet. // // This package also won't work with Go 1.3 and earlier, but making this // runtime version check catch all the earlier versions too, and not just // "1.4.x", isn't worth the complexity. // // TODO: delete this check at some point after Go 1.5 is released. var go1Dot4 = strings.HasPrefix(runtime.Version(), "go1.4.") func init() { if go1Dot4 { log.Println("package webdav requires Go version 1.5 or greater") } } type Handler struct { // Prefix is the URL path prefix to strip from WebDAV resource paths. Prefix string // FileSystem is the virtual file system. FileSystem FileSystem // LockSystem is the lock management system. LockSystem LockSystem // Logger is an optional error logger. If non-nil, it will be called // for all HTTP requests. Logger func(*http.Request, error) } func (h *Handler) stripPrefix(p string) (string, int, error) { if h.Prefix == "" { return p, http.StatusOK, nil } if r := strings.TrimPrefix(p, h.Prefix); len(r) < len(p) { return r, http.StatusOK, nil } return p, http.StatusNotFound, errPrefixMismatch } func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { status, err := http.StatusBadRequest, errUnsupportedMethod if h.FileSystem == nil { status, err = http.StatusInternalServerError, errNoFileSystem } else if h.LockSystem == nil { status, err = http.StatusInternalServerError, errNoLockSystem } else { switch r.Method { case "OPTIONS": status, err = h.handleOptions(w, r) case "GET", "HEAD", "POST": status, err = h.handleGetHeadPost(w, r) case "DELETE": status, err = h.handleDelete(w, r) case "PUT": status, err = h.handlePut(w, r) case "MKCOL": status, err = h.handleMkcol(w, r) case "COPY", "MOVE": status, err = h.handleCopyMove(w, r) case "LOCK": status, err = h.handleLock(w, r) case "UNLOCK": status, err = h.handleUnlock(w, r) case "PROPFIND": status, err = h.handlePropfind(w, r) case "PROPPATCH": status, err = h.handleProppatch(w, r) } } if status != 0 { w.WriteHeader(status) if status != http.StatusNoContent { w.Write([]byte(StatusText(status))) } } if h.Logger != nil { h.Logger(r, err) } } func (h *Handler) lock(now time.Time, root string) (token string, status int, err error) { token, err = h.LockSystem.Create(now, LockDetails{ Root: root, Duration: infiniteTimeout, ZeroDepth: true, }) if err != nil { if err == ErrLocked { return "", StatusLocked, err } return "", http.StatusInternalServerError, err } return token, 0, nil } func (h *Handler) confirmLocks(r *http.Request, src, dst string) (release func(), status int, err error) { hdr := r.Header.Get("If") if hdr == "" { // An empty If header means that the client hasn't previously created locks. // Even if this client doesn't care about locks, we still need to check that // the resources aren't locked by another client, so we create temporary // locks that would conflict with another client's locks. These temporary // locks are unlocked at the end of the HTTP request. now, srcToken, dstToken := time.Now(), "", "" if src != "" { srcToken, status, err = h.lock(now, src) if err != nil { return nil, status, err } } if dst != "" { dstToken, status, err = h.lock(now, dst) if err != nil { if srcToken != "" { h.LockSystem.Unlock(now, srcToken) } return nil, status, err } } return func() { if dstToken != "" { h.LockSystem.Unlock(now, dstToken) } if srcToken != "" { h.LockSystem.Unlock(now, srcToken) } }, 0, nil } ih, ok := parseIfHeader(hdr) if !ok { return nil, http.StatusBadRequest, errInvalidIfHeader } // ih is a disjunction (OR) of ifLists, so any ifList will do. for _, l := range ih.lists { lsrc := l.resourceTag if lsrc == "" { lsrc = src } else { u, err := url.Parse(lsrc) if err != nil { continue } if u.Host != r.Host { continue } lsrc = u.Path } release, err = h.LockSystem.Confirm(time.Now(), lsrc, dst, l.conditions...) if err == ErrConfirmationFailed { continue } if err != nil { return nil, http.StatusInternalServerError, err } return release, 0, nil } // Section 10.4.1 says that "If this header is evaluated and all state lists // fail, then the request must fail with a 412 (Precondition Failed) status." // We follow the spec even though the cond_put_corrupt_token test case from // the litmus test warns on seeing a 412 instead of a 423 (Locked). return nil, http.StatusPreconditionFailed, ErrLocked } func (h *Handler) handleOptions(w http.ResponseWriter, r *http.Request) (status int, err error) { reqPath, status, err := h.stripPrefix(r.URL.Path) if err != nil { return status, err } allow := "OPTIONS, LOCK, PUT, MKCOL" if fi, err := h.FileSystem.Stat(reqPath); err == nil { if fi.IsDir() { allow = "OPTIONS, LOCK, DELETE, PROPPATCH, COPY, MOVE, UNLOCK, PROPFIND" } else { allow = "OPTIONS, LOCK, GET, HEAD, POST, DELETE, PROPPATCH, COPY, MOVE, UNLOCK, PROPFIND, PUT" } } w.Header().Set("Allow", allow) // http://www.webdav.org/specs/rfc4918.html#dav.compliance.classes w.Header().Set("DAV", "1, 2") // http://msdn.microsoft.com/en-au/library/cc250217.aspx w.Header().Set("MS-Author-Via", "DAV") return 0, nil } func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (status int, err error) { reqPath, status, err := h.stripPrefix(r.URL.Path) if err != nil { return status, err } // TODO: check locks for read-only access?? f, err := h.FileSystem.OpenFile(reqPath, os.O_RDONLY, 0) if err != nil { return http.StatusNotFound, err } defer f.Close() fi, err := f.Stat() if err != nil { return http.StatusNotFound, err } if fi.IsDir() { return http.StatusMethodNotAllowed, nil } etag, err := findETag(h.FileSystem, h.LockSystem, reqPath, fi) if err != nil { return http.StatusInternalServerError, err } w.Header().Set("ETag", etag) // Let ServeContent determine the Content-Type header. http.ServeContent(w, r, reqPath, fi.ModTime(), f) return 0, nil } func (h *Handler) handleDelete(w http.ResponseWriter, r *http.Request) (status int, err error) { reqPath, status, err := h.stripPrefix(r.URL.Path) if err != nil { return status, err } release, status, err := h.confirmLocks(r, reqPath, "") if err != nil { return status, err } defer release() // TODO: return MultiStatus where appropriate. // "godoc os RemoveAll" says that "If the path does not exist, RemoveAll // returns nil (no error)." WebDAV semantics are that it should return a // "404 Not Found". We therefore have to Stat before we RemoveAll. if _, err := h.FileSystem.Stat(reqPath); err != nil { if os.IsNotExist(err) { return http.StatusNotFound, err } return http.StatusMethodNotAllowed, err } if err := h.FileSystem.RemoveAll(reqPath); err != nil { return http.StatusMethodNotAllowed, err } return http.StatusNoContent, nil } func (h *Handler) handlePut(w http.ResponseWriter, r *http.Request) (status int, err error) { reqPath, status, err := h.stripPrefix(r.URL.Path) if err != nil { return status, err } release, status, err := h.confirmLocks(r, reqPath, "") if err != nil { return status, err } defer release() // TODO(rost): Support the If-Match, If-None-Match headers? See bradfitz' // comments in http.checkEtag. f, err := h.FileSystem.OpenFile(reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { return http.StatusNotFound, err } _, copyErr := io.Copy(f, r.Body) fi, statErr := f.Stat() closeErr := f.Close() // TODO(rost): Returning 405 Method Not Allowed might not be appropriate. if copyErr != nil { return http.StatusMethodNotAllowed, copyErr } if statErr != nil { return http.StatusMethodNotAllowed, statErr } if closeErr != nil { return http.StatusMethodNotAllowed, closeErr } etag, err := findETag(h.FileSystem, h.LockSystem, reqPath, fi) if err != nil { return http.StatusInternalServerError, err } w.Header().Set("ETag", etag) return http.StatusCreated, nil } func (h *Handler) handleMkcol(w http.ResponseWriter, r *http.Request) (status int, err error) { reqPath, status, err := h.stripPrefix(r.URL.Path) if err != nil { return status, err } release, status, err := h.confirmLocks(r, reqPath, "") if err != nil { return status, err } defer release() if r.ContentLength > 0 { return http.StatusUnsupportedMediaType, nil } if err := h.FileSystem.Mkdir(reqPath, 0777); err != nil { if os.IsNotExist(err) { return http.StatusConflict, err } return http.StatusMethodNotAllowed, err } return http.StatusCreated, nil } func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request) (status int, err error) { hdr := r.Header.Get("Destination") if hdr == "" { return http.StatusBadRequest, errInvalidDestination } u, err := url.Parse(hdr) if err != nil { return http.StatusBadRequest, errInvalidDestination } if u.Host != r.Host { return http.StatusBadGateway, errInvalidDestination } src, status, err := h.stripPrefix(r.URL.Path) if err != nil { return status, err } dst, status, err := h.stripPrefix(u.Path) if err != nil { return status, err } if dst == "" { return http.StatusBadGateway, errInvalidDestination } if dst == src { return http.StatusForbidden, errDestinationEqualsSource } if r.Method == "COPY" { // Section 7.5.1 says that a COPY only needs to lock the destination, // not both destination and source. Strictly speaking, this is racy, // even though a COPY doesn't modify the source, if a concurrent // operation modifies the source. However, the litmus test explicitly // checks that COPYing a locked-by-another source is OK. release, status, err := h.confirmLocks(r, "", dst) if err != nil { return status, err } defer release() // Section 9.8.3 says that "The COPY method on a collection without a Depth // header must act as if a Depth header with value "infinity" was included". depth := infiniteDepth if hdr := r.Header.Get("Depth"); hdr != "" { depth = parseDepth(hdr) if depth != 0 && depth != infiniteDepth { // Section 9.8.3 says that "A client may submit a Depth header on a // COPY on a collection with a value of "0" or "infinity"." return http.StatusBadRequest, errInvalidDepth } } return copyFiles(h.FileSystem, src, dst, r.Header.Get("Overwrite") != "F", depth, 0) } release, status, err := h.confirmLocks(r, src, dst) if err != nil { return status, err } defer release() // Section 9.9.2 says that "The MOVE method on a collection must act as if // a "Depth: infinity" header was used on it. A client must not submit a // Depth header on a MOVE on a collection with any value but "infinity"." if hdr := r.Header.Get("Depth"); hdr != "" { if parseDepth(hdr) != infiniteDepth { return http.StatusBadRequest, errInvalidDepth } } return moveFiles(h.FileSystem, src, dst, r.Header.Get("Overwrite") == "T") } func (h *Handler) handleLock(w http.ResponseWriter, r *http.Request) (retStatus int, retErr error) { duration, err := parseTimeout(r.Header.Get("Timeout")) if err != nil { return http.StatusBadRequest, err } li, status, err := readLockInfo(r.Body) if err != nil { return status, err } token, ld, now, created := "", LockDetails{}, time.Now(), false if li == (lockInfo{}) { // An empty lockInfo means to refresh the lock. ih, ok := parseIfHeader(r.Header.Get("If")) if !ok { return http.StatusBadRequest, errInvalidIfHeader } if len(ih.lists) == 1 && len(ih.lists[0].conditions) == 1 { token = ih.lists[0].conditions[0].Token } if token == "" { return http.StatusBadRequest, errInvalidLockToken } ld, err = h.LockSystem.Refresh(now, token, duration) if err != nil { if err == ErrNoSuchLock { return http.StatusPreconditionFailed, err } return http.StatusInternalServerError, err } } else { // Section 9.10.3 says that "If no Depth header is submitted on a LOCK request, // then the request MUST act as if a "Depth:infinity" had been submitted." depth := infiniteDepth if hdr := r.Header.Get("Depth"); hdr != "" { depth = parseDepth(hdr) if depth != 0 && depth != infiniteDepth { // Section 9.10.3 says that "Values other than 0 or infinity must not be // used with the Depth header on a LOCK method". return http.StatusBadRequest, errInvalidDepth } } reqPath, status, err := h.stripPrefix(r.URL.Path) if err != nil { return status, err } ld = LockDetails{ Root: reqPath, Duration: duration, OwnerXML: li.Owner.InnerXML, ZeroDepth: depth == 0, } token, err = h.LockSystem.Create(now, ld) if err != nil { if err == ErrLocked { return StatusLocked, err } return http.StatusInternalServerError, err } defer func() { if retErr != nil { h.LockSystem.Unlock(now, token) } }() // Create the resource if it didn't previously exist. if _, err := h.FileSystem.Stat(reqPath); err != nil { f, err := h.FileSystem.OpenFile(reqPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { // TODO: detect missing intermediate dirs and return http.StatusConflict? return http.StatusInternalServerError, err } f.Close() created = true } // http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token says that the // Lock-Token value is a Coded-URL. We add angle brackets. w.Header().Set("Lock-Token", "<"+token+">") } w.Header().Set("Content-Type", "application/xml; charset=utf-8") if created { // This is "w.WriteHeader(http.StatusCreated)" and not "return // http.StatusCreated, nil" because we write our own (XML) response to w // and Handler.ServeHTTP would otherwise write "Created". w.WriteHeader(http.StatusCreated) } writeLockInfo(w, token, ld) return 0, nil } func (h *Handler) handleUnlock(w http.ResponseWriter, r *http.Request) (status int, err error) { // http://www.webdav.org/specs/rfc4918.html#HEADER_Lock-Token says that the // Lock-Token value is a Coded-URL. We strip its angle brackets. t := r.Header.Get("Lock-Token") if len(t) < 2 || t[0] != '<' || t[len(t)-1] != '>' { return http.StatusBadRequest, errInvalidLockToken } t = t[1 : len(t)-1] switch err = h.LockSystem.Unlock(time.Now(), t); err { case nil: return http.StatusNoContent, err case ErrForbidden: return http.StatusForbidden, err case ErrLocked: return StatusLocked, err case ErrNoSuchLock: return http.StatusConflict, err default: return http.StatusInternalServerError, err } } func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request) (status int, err error) { reqPath, status, err := h.stripPrefix(r.URL.Path) if err != nil { return status, err } fi, err := h.FileSystem.Stat(reqPath) if err != nil { if os.IsNotExist(err) { return http.StatusNotFound, err } return http.StatusMethodNotAllowed, err } depth := infiniteDepth if hdr := r.Header.Get("Depth"); hdr != "" { depth = parseDepth(hdr) if depth == invalidDepth { return http.StatusBadRequest, errInvalidDepth } } pf, status, err := readPropfind(r.Body) if err != nil { return status, err } mw := multistatusWriter{w: w} walkFn := func(reqPath string, info os.FileInfo, err error) error { if err != nil { return err } var pstats []Propstat if pf.Propname != nil { pnames, err := propnames(h.FileSystem, h.LockSystem, reqPath) if err != nil { return err } pstat := Propstat{Status: http.StatusOK} for _, xmlname := range pnames { pstat.Props = append(pstat.Props, Property{XMLName: xmlname}) } pstats = append(pstats, pstat) } else if pf.Allprop != nil { pstats, err = allprop(h.FileSystem, h.LockSystem, reqPath, pf.Prop) } else { pstats, err = props(h.FileSystem, h.LockSystem, reqPath, pf.Prop) } if err != nil { return err } return mw.write(makePropstatResponse(path.Join(h.Prefix, reqPath), pstats)) } walkErr := walkFS(h.FileSystem, depth, reqPath, fi, walkFn) closeErr := mw.close() if walkErr != nil { return http.StatusInternalServerError, walkErr } if closeErr != nil { return http.StatusInternalServerError, closeErr } return 0, nil } func (h *Handler) handleProppatch(w http.ResponseWriter, r *http.Request) (status int, err error) { reqPath, status, err := h.stripPrefix(r.URL.Path) if err != nil { return status, err } release, status, err := h.confirmLocks(r, reqPath, "") if err != nil { return status, err } defer release() if _, err := h.FileSystem.Stat(reqPath); err != nil { if os.IsNotExist(err) { return http.StatusNotFound, err } return http.StatusMethodNotAllowed, err } patches, status, err := readProppatch(r.Body) if err != nil { return status, err } pstats, err := patch(h.FileSystem, h.LockSystem, reqPath, patches) if err != nil { return http.StatusInternalServerError, err } mw := multistatusWriter{w: w} writeErr := mw.write(makePropstatResponse(r.URL.Path, pstats)) closeErr := mw.close() if writeErr != nil { return http.StatusInternalServerError, writeErr } if closeErr != nil { return http.StatusInternalServerError, closeErr } return 0, nil } func makePropstatResponse(href string, pstats []Propstat) *response { resp := response{ Href: []string{(&url.URL{Path: href}).EscapedPath()}, Propstat: make([]propstat, 0, len(pstats)), } for _, p := range pstats { var xmlErr *xmlError if p.XMLError != "" { xmlErr = &xmlError{InnerXML: []byte(p.XMLError)} } resp.Propstat = append(resp.Propstat, propstat{ Status: fmt.Sprintf("HTTP/1.1 %d %s", p.Status, StatusText(p.Status)), Prop: p.Props, ResponseDescription: p.ResponseDescription, Error: xmlErr, }) } return &resp } const ( infiniteDepth = -1 invalidDepth = -2 ) // parseDepth maps the strings "0", "1" and "infinity" to 0, 1 and // infiniteDepth. Parsing any other string returns invalidDepth. // // Different WebDAV methods have further constraints on valid depths: // - PROPFIND has no further restrictions, as per section 9.1. // - COPY accepts only "0" or "infinity", as per section 9.8.3. // - MOVE accepts only "infinity", as per section 9.9.2. // - LOCK accepts only "0" or "infinity", as per section 9.10.3. // These constraints are enforced by the handleXxx methods. func parseDepth(s string) int { switch s { case "0": return 0 case "1": return 1 case "infinity": return infiniteDepth } return invalidDepth } // http://www.webdav.org/specs/rfc4918.html#status.code.extensions.to.http11 const ( StatusMulti = 207 StatusUnprocessableEntity = 422 StatusLocked = 423 StatusFailedDependency = 424 StatusInsufficientStorage = 507 ) func StatusText(code int) string { switch code { case StatusMulti: return "Multi-Status" case StatusUnprocessableEntity: return "Unprocessable Entity" case StatusLocked: return "Locked" case StatusFailedDependency: return "Failed Dependency" case StatusInsufficientStorage: return "Insufficient Storage" } return http.StatusText(code) } var ( errDestinationEqualsSource = errors.New("webdav: destination equals source") errDirectoryNotEmpty = errors.New("webdav: directory not empty") errInvalidDepth = errors.New("webdav: invalid depth") errInvalidDestination = errors.New("webdav: invalid destination") errInvalidIfHeader = errors.New("webdav: invalid If header") errInvalidLockInfo = errors.New("webdav: invalid lock info") errInvalidLockToken = errors.New("webdav: invalid lock token") errInvalidPropfind = errors.New("webdav: invalid propfind") errInvalidProppatch = errors.New("webdav: invalid proppatch") errInvalidResponse = errors.New("webdav: invalid response") errInvalidTimeout = errors.New("webdav: invalid timeout") errNoFileSystem = errors.New("webdav: no file system") errNoLockSystem = errors.New("webdav: no lock system") errNotADirectory = errors.New("webdav: not a directory") errPrefixMismatch = errors.New("webdav: prefix mismatch") errRecursionTooDeep = errors.New("webdav: recursion too deep") errUnsupportedLockInfo = errors.New("webdav: unsupported lock info") errUnsupportedMethod = errors.New("webdav: unsupported method") ) golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/webdav_test.go000066400000000000000000000133351264464372400245530ustar00rootroot00000000000000// Copyright 2015 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 webdav import ( "errors" "fmt" "io" "io/ioutil" "net/http" "net/http/httptest" "net/url" "os" "reflect" "regexp" "sort" "strings" "testing" ) // TODO: add tests to check XML responses with the expected prefix path func TestPrefix(t *testing.T) { const dst, blah = "Destination", "blah blah blah" do := func(method, urlStr string, body io.Reader, wantStatusCode int, headers ...string) error { req, err := http.NewRequest(method, urlStr, body) if err != nil { return err } for len(headers) >= 2 { req.Header.Add(headers[0], headers[1]) headers = headers[2:] } res, err := http.DefaultClient.Do(req) if err != nil { return err } defer res.Body.Close() if res.StatusCode != wantStatusCode { return fmt.Errorf("got status code %d, want %d", res.StatusCode, wantStatusCode) } return nil } prefixes := []string{ "/", "/a/", "/a/b/", "/a/b/c/", } for _, prefix := range prefixes { fs := NewMemFS() h := &Handler{ FileSystem: fs, LockSystem: NewMemLS(), } mux := http.NewServeMux() if prefix != "/" { h.Prefix = prefix } mux.Handle(prefix, h) srv := httptest.NewServer(mux) defer srv.Close() // The script is: // MKCOL /a // MKCOL /a/b // PUT /a/b/c // COPY /a/b/c /a/b/d // MKCOL /a/b/e // MOVE /a/b/d /a/b/e/f // which should yield the (possibly stripped) filenames /a/b/c and // /a/b/e/f, plus their parent directories. wantA := map[string]int{ "/": http.StatusCreated, "/a/": http.StatusMovedPermanently, "/a/b/": http.StatusNotFound, "/a/b/c/": http.StatusNotFound, }[prefix] if err := do("MKCOL", srv.URL+"/a", nil, wantA); err != nil { t.Errorf("prefix=%-9q MKCOL /a: %v", prefix, err) continue } wantB := map[string]int{ "/": http.StatusCreated, "/a/": http.StatusCreated, "/a/b/": http.StatusMovedPermanently, "/a/b/c/": http.StatusNotFound, }[prefix] if err := do("MKCOL", srv.URL+"/a/b", nil, wantB); err != nil { t.Errorf("prefix=%-9q MKCOL /a/b: %v", prefix, err) continue } wantC := map[string]int{ "/": http.StatusCreated, "/a/": http.StatusCreated, "/a/b/": http.StatusCreated, "/a/b/c/": http.StatusMovedPermanently, }[prefix] if err := do("PUT", srv.URL+"/a/b/c", strings.NewReader(blah), wantC); err != nil { t.Errorf("prefix=%-9q PUT /a/b/c: %v", prefix, err) continue } wantD := map[string]int{ "/": http.StatusCreated, "/a/": http.StatusCreated, "/a/b/": http.StatusCreated, "/a/b/c/": http.StatusMovedPermanently, }[prefix] if err := do("COPY", srv.URL+"/a/b/c", nil, wantD, dst, srv.URL+"/a/b/d"); err != nil { t.Errorf("prefix=%-9q COPY /a/b/c /a/b/d: %v", prefix, err) continue } wantE := map[string]int{ "/": http.StatusCreated, "/a/": http.StatusCreated, "/a/b/": http.StatusCreated, "/a/b/c/": http.StatusNotFound, }[prefix] if err := do("MKCOL", srv.URL+"/a/b/e", nil, wantE); err != nil { t.Errorf("prefix=%-9q MKCOL /a/b/e: %v", prefix, err) continue } wantF := map[string]int{ "/": http.StatusCreated, "/a/": http.StatusCreated, "/a/b/": http.StatusCreated, "/a/b/c/": http.StatusNotFound, }[prefix] if err := do("MOVE", srv.URL+"/a/b/d", nil, wantF, dst, srv.URL+"/a/b/e/f"); err != nil { t.Errorf("prefix=%-9q MOVE /a/b/d /a/b/e/f: %v", prefix, err) continue } got, err := find(nil, fs, "/") if err != nil { t.Errorf("prefix=%-9q find: %v", prefix, err) continue } sort.Strings(got) want := map[string][]string{ "/": []string{"/", "/a", "/a/b", "/a/b/c", "/a/b/e", "/a/b/e/f"}, "/a/": []string{"/", "/b", "/b/c", "/b/e", "/b/e/f"}, "/a/b/": []string{"/", "/c", "/e", "/e/f"}, "/a/b/c/": []string{"/"}, }[prefix] if !reflect.DeepEqual(got, want) { t.Errorf("prefix=%-9q find:\ngot %v\nwant %v", prefix, got, want) continue } } } func TestFilenameEscape(t *testing.T) { re := regexp.MustCompile(`([^<]*)`) do := func(method, urlStr string) (string, error) { req, err := http.NewRequest(method, urlStr, nil) if err != nil { return "", err } res, err := http.DefaultClient.Do(req) if err != nil { return "", err } defer res.Body.Close() b, err := ioutil.ReadAll(res.Body) if err != nil { return "", err } m := re.FindStringSubmatch(string(b)) if len(m) != 2 { return "", errors.New("D:href not found") } return m[1], nil } testCases := []struct { name, want string }{{ name: `/foo%bar`, want: `/foo%25bar`, }, { name: `/ã“ã‚“ã«ã¡ã‚世界`, want: `/%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%82%8F%E4%B8%96%E7%95%8C`, }, { name: `/Program Files/`, want: `/Program%20Files`, }, { name: `/go+lang`, want: `/go+lang`, }, { name: `/go&lang`, want: `/go&lang`, }} fs := NewMemFS() for _, tc := range testCases { if strings.HasSuffix(tc.name, "/") { if err := fs.Mkdir(tc.name, 0755); err != nil { t.Fatalf("name=%q: Mkdir: %v", tc.name, err) } } else { f, err := fs.OpenFile(tc.name, os.O_CREATE, 0644) if err != nil { t.Fatalf("name=%q: OpenFile: %v", tc.name, err) } f.Close() } } srv := httptest.NewServer(&Handler{ FileSystem: fs, LockSystem: NewMemLS(), }) defer srv.Close() u, err := url.Parse(srv.URL) if err != nil { t.Fatal(err) } for _, tc := range testCases { u.Path = tc.name got, err := do("PROPFIND", u.String()) if err != nil { t.Errorf("name=%q: PROPFIND: %v", tc.name, err) continue } if got != tc.want { t.Errorf("name=%q: got %q, want %q", tc.name, got, tc.want) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/xml.go000066400000000000000000000334751264464372400230530ustar00rootroot00000000000000// Copyright 2014 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 webdav // The XML encoding is covered by Section 14. // http://www.webdav.org/specs/rfc4918.html#xml.element.definitions import ( "bytes" "fmt" "io" "net/http" "time" "golang.org/x/net/webdav/internal/xml" ) // http://www.webdav.org/specs/rfc4918.html#ELEMENT_lockinfo type lockInfo struct { XMLName xml.Name `xml:"lockinfo"` Exclusive *struct{} `xml:"lockscope>exclusive"` Shared *struct{} `xml:"lockscope>shared"` Write *struct{} `xml:"locktype>write"` Owner owner `xml:"owner"` } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_owner type owner struct { InnerXML string `xml:",innerxml"` } func readLockInfo(r io.Reader) (li lockInfo, status int, err error) { c := &countingReader{r: r} if err = xml.NewDecoder(c).Decode(&li); err != nil { if err == io.EOF { if c.n == 0 { // An empty body means to refresh the lock. // http://www.webdav.org/specs/rfc4918.html#refreshing-locks return lockInfo{}, 0, nil } err = errInvalidLockInfo } return lockInfo{}, http.StatusBadRequest, err } // We only support exclusive (non-shared) write locks. In practice, these are // the only types of locks that seem to matter. if li.Exclusive == nil || li.Shared != nil || li.Write == nil { return lockInfo{}, http.StatusNotImplemented, errUnsupportedLockInfo } return li, 0, nil } type countingReader struct { n int r io.Reader } func (c *countingReader) Read(p []byte) (int, error) { n, err := c.r.Read(p) c.n += n return n, err } func writeLockInfo(w io.Writer, token string, ld LockDetails) (int, error) { depth := "infinity" if ld.ZeroDepth { depth = "0" } timeout := ld.Duration / time.Second return fmt.Fprintf(w, "\n"+ "\n"+ " \n"+ " \n"+ " %s\n"+ " %s\n"+ " Second-%d\n"+ " %s\n"+ " %s\n"+ "", depth, ld.OwnerXML, timeout, escape(token), escape(ld.Root), ) } func escape(s string) string { for i := 0; i < len(s); i++ { switch s[i] { case '"', '&', '\'', '<', '>': b := bytes.NewBuffer(nil) xml.EscapeText(b, []byte(s)) return b.String() } } return s } // Next returns the next token, if any, in the XML stream of d. // RFC 4918 requires to ignore comments, processing instructions // and directives. // http://www.webdav.org/specs/rfc4918.html#property_values // http://www.webdav.org/specs/rfc4918.html#xml-extensibility func next(d *xml.Decoder) (xml.Token, error) { for { t, err := d.Token() if err != nil { return t, err } switch t.(type) { case xml.Comment, xml.Directive, xml.ProcInst: continue default: return t, nil } } } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_prop (for propfind) type propfindProps []xml.Name // UnmarshalXML appends the property names enclosed within start to pn. // // It returns an error if start does not contain any properties or if // properties contain values. Character data between properties is ignored. func (pn *propfindProps) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { for { t, err := next(d) if err != nil { return err } switch t.(type) { case xml.EndElement: if len(*pn) == 0 { return fmt.Errorf("%s must not be empty", start.Name.Local) } return nil case xml.StartElement: name := t.(xml.StartElement).Name t, err = next(d) if err != nil { return err } if _, ok := t.(xml.EndElement); !ok { return fmt.Errorf("unexpected token %T", t) } *pn = append(*pn, name) } } } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_propfind type propfind struct { XMLName xml.Name `xml:"DAV: propfind"` Allprop *struct{} `xml:"DAV: allprop"` Propname *struct{} `xml:"DAV: propname"` Prop propfindProps `xml:"DAV: prop"` Include propfindProps `xml:"DAV: include"` } func readPropfind(r io.Reader) (pf propfind, status int, err error) { c := countingReader{r: r} if err = xml.NewDecoder(&c).Decode(&pf); err != nil { if err == io.EOF { if c.n == 0 { // An empty body means to propfind allprop. // http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND return propfind{Allprop: new(struct{})}, 0, nil } err = errInvalidPropfind } return propfind{}, http.StatusBadRequest, err } if pf.Allprop == nil && pf.Include != nil { return propfind{}, http.StatusBadRequest, errInvalidPropfind } if pf.Allprop != nil && (pf.Prop != nil || pf.Propname != nil) { return propfind{}, http.StatusBadRequest, errInvalidPropfind } if pf.Prop != nil && pf.Propname != nil { return propfind{}, http.StatusBadRequest, errInvalidPropfind } if pf.Propname == nil && pf.Allprop == nil && pf.Prop == nil { return propfind{}, http.StatusBadRequest, errInvalidPropfind } return pf, 0, nil } // Property represents a single DAV resource property as defined in RFC 4918. // See http://www.webdav.org/specs/rfc4918.html#data.model.for.resource.properties type Property struct { // XMLName is the fully qualified name that identifies this property. XMLName xml.Name // Lang is an optional xml:lang attribute. Lang string `xml:"xml:lang,attr,omitempty"` // InnerXML contains the XML representation of the property value. // See http://www.webdav.org/specs/rfc4918.html#property_values // // Property values of complex type or mixed-content must have fully // expanded XML namespaces or be self-contained with according // XML namespace declarations. They must not rely on any XML // namespace declarations within the scope of the XML document, // even including the DAV: namespace. InnerXML []byte `xml:",innerxml"` } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_error // See multistatusWriter for the "D:" namespace prefix. type xmlError struct { XMLName xml.Name `xml:"D:error"` InnerXML []byte `xml:",innerxml"` } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_propstat // See multistatusWriter for the "D:" namespace prefix. type propstat struct { Prop []Property `xml:"D:prop>_ignored_"` Status string `xml:"D:status"` Error *xmlError `xml:"D:error"` ResponseDescription string `xml:"D:responsedescription,omitempty"` } // MarshalXML prepends the "D:" namespace prefix on properties in the DAV: namespace // before encoding. See multistatusWriter. func (ps propstat) MarshalXML(e *xml.Encoder, start xml.StartElement) error { for k, prop := range ps.Prop { if prop.XMLName.Space == "DAV:" { prop.XMLName = xml.Name{Space: "", Local: "D:" + prop.XMLName.Local} ps.Prop[k] = prop } } // Distinct type to avoid infinite recursion of MarshalXML. type newpropstat propstat return e.EncodeElement(newpropstat(ps), start) } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_response // See multistatusWriter for the "D:" namespace prefix. type response struct { XMLName xml.Name `xml:"D:response"` Href []string `xml:"D:href"` Propstat []propstat `xml:"D:propstat"` Status string `xml:"D:status,omitempty"` Error *xmlError `xml:"D:error"` ResponseDescription string `xml:"D:responsedescription,omitempty"` } // MultistatusWriter marshals one or more Responses into a XML // multistatus response. // See http://www.webdav.org/specs/rfc4918.html#ELEMENT_multistatus // TODO(rsto, mpl): As a workaround, the "D:" namespace prefix, defined as // "DAV:" on this element, is prepended on the nested response, as well as on all // its nested elements. All property names in the DAV: namespace are prefixed as // well. This is because some versions of Mini-Redirector (on windows 7) ignore // elements with a default namespace (no prefixed namespace). A less intrusive fix // should be possible after golang.org/cl/11074. See https://golang.org/issue/11177 type multistatusWriter struct { // ResponseDescription contains the optional responsedescription // of the multistatus XML element. Only the latest content before // close will be emitted. Empty response descriptions are not // written. responseDescription string w http.ResponseWriter enc *xml.Encoder } // Write validates and emits a DAV response as part of a multistatus response // element. // // It sets the HTTP status code of its underlying http.ResponseWriter to 207 // (Multi-Status) and populates the Content-Type header. If r is the // first, valid response to be written, Write prepends the XML representation // of r with a multistatus tag. Callers must call close after the last response // has been written. func (w *multistatusWriter) write(r *response) error { switch len(r.Href) { case 0: return errInvalidResponse case 1: if len(r.Propstat) > 0 != (r.Status == "") { return errInvalidResponse } default: if len(r.Propstat) > 0 || r.Status == "" { return errInvalidResponse } } err := w.writeHeader() if err != nil { return err } return w.enc.Encode(r) } // writeHeader writes a XML multistatus start element on w's underlying // http.ResponseWriter and returns the result of the write operation. // After the first write attempt, writeHeader becomes a no-op. func (w *multistatusWriter) writeHeader() error { if w.enc != nil { return nil } w.w.Header().Add("Content-Type", "text/xml; charset=utf-8") w.w.WriteHeader(StatusMulti) _, err := fmt.Fprintf(w.w, ``) if err != nil { return err } w.enc = xml.NewEncoder(w.w) return w.enc.EncodeToken(xml.StartElement{ Name: xml.Name{ Space: "DAV:", Local: "multistatus", }, Attr: []xml.Attr{{ Name: xml.Name{Space: "xmlns", Local: "D"}, Value: "DAV:", }}, }) } // Close completes the marshalling of the multistatus response. It returns // an error if the multistatus response could not be completed. If both the // return value and field enc of w are nil, then no multistatus response has // been written. func (w *multistatusWriter) close() error { if w.enc == nil { return nil } var end []xml.Token if w.responseDescription != "" { name := xml.Name{Space: "DAV:", Local: "responsedescription"} end = append(end, xml.StartElement{Name: name}, xml.CharData(w.responseDescription), xml.EndElement{Name: name}, ) } end = append(end, xml.EndElement{ Name: xml.Name{Space: "DAV:", Local: "multistatus"}, }) for _, t := range end { err := w.enc.EncodeToken(t) if err != nil { return err } } return w.enc.Flush() } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_prop (for proppatch) type proppatchProps []Property var xmlLangName = xml.Name{Space: "http://www.w3.org/XML/1998/namespace", Local: "lang"} func xmlLang(s xml.StartElement, d string) string { for _, attr := range s.Attr { if attr.Name == xmlLangName { return attr.Value } } return d } type xmlValue []byte func (v *xmlValue) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { // The XML value of a property can be arbitrary, mixed-content XML. // To make sure that the unmarshalled value contains all required // namespaces, we encode all the property value XML tokens into a // buffer. This forces the encoder to redeclare any used namespaces. var b bytes.Buffer e := xml.NewEncoder(&b) for { t, err := next(d) if err != nil { return err } if e, ok := t.(xml.EndElement); ok && e.Name == start.Name { break } if err = e.EncodeToken(t); err != nil { return err } } err := e.Flush() if err != nil { return err } *v = b.Bytes() return nil } // UnmarshalXML appends the property names and values enclosed within start // to ps. // // An xml:lang attribute that is defined either on the DAV:prop or property // name XML element is propagated to the property's Lang field. // // UnmarshalXML returns an error if start does not contain any properties or if // property values contain syntactically incorrect XML. func (ps *proppatchProps) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { lang := xmlLang(start, "") for { t, err := next(d) if err != nil { return err } switch elem := t.(type) { case xml.EndElement: if len(*ps) == 0 { return fmt.Errorf("%s must not be empty", start.Name.Local) } return nil case xml.StartElement: p := Property{ XMLName: t.(xml.StartElement).Name, Lang: xmlLang(t.(xml.StartElement), lang), } err = d.DecodeElement(((*xmlValue)(&p.InnerXML)), &elem) if err != nil { return err } *ps = append(*ps, p) } } } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_set // http://www.webdav.org/specs/rfc4918.html#ELEMENT_remove type setRemove struct { XMLName xml.Name Lang string `xml:"xml:lang,attr,omitempty"` Prop proppatchProps `xml:"DAV: prop"` } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_propertyupdate type propertyupdate struct { XMLName xml.Name `xml:"DAV: propertyupdate"` Lang string `xml:"xml:lang,attr,omitempty"` SetRemove []setRemove `xml:",any"` } func readProppatch(r io.Reader) (patches []Proppatch, status int, err error) { var pu propertyupdate if err = xml.NewDecoder(r).Decode(&pu); err != nil { return nil, http.StatusBadRequest, err } for _, op := range pu.SetRemove { remove := false switch op.XMLName { case xml.Name{Space: "DAV:", Local: "set"}: // No-op. case xml.Name{Space: "DAV:", Local: "remove"}: for _, p := range op.Prop { if len(p.InnerXML) > 0 { return nil, http.StatusBadRequest, errInvalidProppatch } } remove = true default: return nil, http.StatusBadRequest, errInvalidProppatch } patches = append(patches, Proppatch{Remove: remove, Props: op.Prop}) } return patches, 0, nil } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/webdav/xml_test.go000066400000000000000000000617371264464372400241140ustar00rootroot00000000000000// Copyright 2014 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 webdav import ( "bytes" "fmt" "io" "net/http" "net/http/httptest" "reflect" "sort" "strings" "testing" "golang.org/x/net/webdav/internal/xml" ) func TestReadLockInfo(t *testing.T) { // The "section x.y.z" test cases come from section x.y.z of the spec at // http://www.webdav.org/specs/rfc4918.html testCases := []struct { desc string input string wantLI lockInfo wantStatus int }{{ "bad: junk", "xxx", lockInfo{}, http.StatusBadRequest, }, { "bad: invalid owner XML", "" + "\n" + " \n" + " \n" + " \n" + " no end tag \n" + " \n" + "", lockInfo{}, http.StatusBadRequest, }, { "bad: invalid UTF-8", "" + "\n" + " \n" + " \n" + " \n" + " \xff \n" + " \n" + "", lockInfo{}, http.StatusBadRequest, }, { "bad: unfinished XML #1", "" + "\n" + " \n" + " \n", lockInfo{}, http.StatusBadRequest, }, { "bad: unfinished XML #2", "" + "\n" + " \n" + " \n" + " \n", lockInfo{}, http.StatusBadRequest, }, { "good: empty", "", lockInfo{}, 0, }, { "good: plain-text owner", "" + "\n" + " \n" + " \n" + " gopher\n" + "", lockInfo{ XMLName: xml.Name{Space: "DAV:", Local: "lockinfo"}, Exclusive: new(struct{}), Write: new(struct{}), Owner: owner{ InnerXML: "gopher", }, }, 0, }, { "section 9.10.7", "" + "\n" + " \n" + " \n" + " \n" + " http://example.org/~ejw/contact.html\n" + " \n" + "", lockInfo{ XMLName: xml.Name{Space: "DAV:", Local: "lockinfo"}, Exclusive: new(struct{}), Write: new(struct{}), Owner: owner{ InnerXML: "\n http://example.org/~ejw/contact.html\n ", }, }, 0, }} for _, tc := range testCases { li, status, err := readLockInfo(strings.NewReader(tc.input)) if tc.wantStatus != 0 { if err == nil { t.Errorf("%s: got nil error, want non-nil", tc.desc) continue } } else if err != nil { t.Errorf("%s: %v", tc.desc, err) continue } if !reflect.DeepEqual(li, tc.wantLI) || status != tc.wantStatus { t.Errorf("%s:\ngot lockInfo=%v, status=%v\nwant lockInfo=%v, status=%v", tc.desc, li, status, tc.wantLI, tc.wantStatus) continue } } } func TestReadPropfind(t *testing.T) { testCases := []struct { desc string input string wantPF propfind wantStatus int }{{ desc: "propfind: propname", input: "" + "\n" + " \n" + "", wantPF: propfind{ XMLName: xml.Name{Space: "DAV:", Local: "propfind"}, Propname: new(struct{}), }, }, { desc: "propfind: empty body means allprop", input: "", wantPF: propfind{ Allprop: new(struct{}), }, }, { desc: "propfind: allprop", input: "" + "\n" + " \n" + "", wantPF: propfind{ XMLName: xml.Name{Space: "DAV:", Local: "propfind"}, Allprop: new(struct{}), }, }, { desc: "propfind: allprop followed by include", input: "" + "\n" + " \n" + " \n" + "", wantPF: propfind{ XMLName: xml.Name{Space: "DAV:", Local: "propfind"}, Allprop: new(struct{}), Include: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, }, }, { desc: "propfind: include followed by allprop", input: "" + "\n" + " \n" + " \n" + "", wantPF: propfind{ XMLName: xml.Name{Space: "DAV:", Local: "propfind"}, Allprop: new(struct{}), Include: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, }, }, { desc: "propfind: propfind", input: "" + "\n" + " \n" + "", wantPF: propfind{ XMLName: xml.Name{Space: "DAV:", Local: "propfind"}, Prop: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, }, }, { desc: "propfind: prop with ignored comments", input: "" + "\n" + " \n" + " \n" + " \n" + " \n" + "", wantPF: propfind{ XMLName: xml.Name{Space: "DAV:", Local: "propfind"}, Prop: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, }, }, { desc: "propfind: propfind with ignored whitespace", input: "" + "\n" + " \n" + "", wantPF: propfind{ XMLName: xml.Name{Space: "DAV:", Local: "propfind"}, Prop: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, }, }, { desc: "propfind: propfind with ignored mixed-content", input: "" + "\n" + " foobar\n" + "", wantPF: propfind{ XMLName: xml.Name{Space: "DAV:", Local: "propfind"}, Prop: propfindProps{xml.Name{Space: "DAV:", Local: "displayname"}}, }, }, { desc: "propfind: propname with ignored element (section A.4)", input: "" + "\n" + " \n" + " *boss*\n" + "", wantPF: propfind{ XMLName: xml.Name{Space: "DAV:", Local: "propfind"}, Propname: new(struct{}), }, }, { desc: "propfind: bad: junk", input: "xxx", wantStatus: http.StatusBadRequest, }, { desc: "propfind: bad: propname and allprop (section A.3)", input: "" + "\n" + " " + " " + "", wantStatus: http.StatusBadRequest, }, { desc: "propfind: bad: propname and prop", input: "" + "\n" + " \n" + " \n" + "", wantStatus: http.StatusBadRequest, }, { desc: "propfind: bad: allprop and prop", input: "" + "\n" + " \n" + " \n" + "", wantStatus: http.StatusBadRequest, }, { desc: "propfind: bad: empty propfind with ignored element (section A.4)", input: "" + "\n" + " \n" + "", wantStatus: http.StatusBadRequest, }, { desc: "propfind: bad: empty prop", input: "" + "\n" + " \n" + "", wantStatus: http.StatusBadRequest, }, { desc: "propfind: bad: prop with just chardata", input: "" + "\n" + " foo\n" + "", wantStatus: http.StatusBadRequest, }, { desc: "bad: interrupted prop", input: "" + "\n" + " \n", wantStatus: http.StatusBadRequest, }, { desc: "bad: malformed end element prop", input: "" + "\n" + " \n", wantStatus: http.StatusBadRequest, }, { desc: "propfind: bad: property with chardata value", input: "" + "\n" + " bar\n" + "", wantStatus: http.StatusBadRequest, }, { desc: "propfind: bad: property with whitespace value", input: "" + "\n" + " \n" + "", wantStatus: http.StatusBadRequest, }, { desc: "propfind: bad: include without allprop", input: "" + "\n" + " \n" + "", wantStatus: http.StatusBadRequest, }} for _, tc := range testCases { pf, status, err := readPropfind(strings.NewReader(tc.input)) if tc.wantStatus != 0 { if err == nil { t.Errorf("%s: got nil error, want non-nil", tc.desc) continue } } else if err != nil { t.Errorf("%s: %v", tc.desc, err) continue } if !reflect.DeepEqual(pf, tc.wantPF) || status != tc.wantStatus { t.Errorf("%s:\ngot propfind=%v, status=%v\nwant propfind=%v, status=%v", tc.desc, pf, status, tc.wantPF, tc.wantStatus) continue } } } func TestMultistatusWriter(t *testing.T) { if go1Dot4 { t.Skip("TestMultistatusWriter requires Go version 1.5 or greater") } ///The "section x.y.z" test cases come from section x.y.z of the spec at // http://www.webdav.org/specs/rfc4918.html testCases := []struct { desc string responses []response respdesc string writeHeader bool wantXML string wantCode int wantErr error }{{ desc: "section 9.2.2 (failed dependency)", responses: []response{{ Href: []string{"http://example.com/foo"}, Propstat: []propstat{{ Prop: []Property{{ XMLName: xml.Name{ Space: "http://ns.example.com/", Local: "Authors", }, }}, Status: "HTTP/1.1 424 Failed Dependency", }, { Prop: []Property{{ XMLName: xml.Name{ Space: "http://ns.example.com/", Local: "Copyright-Owner", }, }}, Status: "HTTP/1.1 409 Conflict", }}, ResponseDescription: "Copyright Owner cannot be deleted or altered.", }}, wantXML: `` + `` + `` + ` ` + ` http://example.com/foo` + ` ` + ` ` + ` ` + ` ` + ` HTTP/1.1 424 Failed Dependency` + ` ` + ` ` + ` ` + ` ` + ` ` + ` HTTP/1.1 409 Conflict` + ` ` + ` Copyright Owner cannot be deleted or altered.` + `` + ``, wantCode: StatusMulti, }, { desc: "section 9.6.2 (lock-token-submitted)", responses: []response{{ Href: []string{"http://example.com/foo"}, Status: "HTTP/1.1 423 Locked", Error: &xmlError{ InnerXML: []byte(``), }, }}, wantXML: `` + `` + `` + ` ` + ` http://example.com/foo` + ` HTTP/1.1 423 Locked` + ` ` + ` ` + ``, wantCode: StatusMulti, }, { desc: "section 9.1.3", responses: []response{{ Href: []string{"http://example.com/foo"}, Propstat: []propstat{{ Prop: []Property{{ XMLName: xml.Name{Space: "http://ns.example.com/boxschema/", Local: "bigbox"}, InnerXML: []byte(`` + `` + `Box type A` + ``), }, { XMLName: xml.Name{Space: "http://ns.example.com/boxschema/", Local: "author"}, InnerXML: []byte(`` + `` + `J.J. Johnson` + ``), }}, Status: "HTTP/1.1 200 OK", }, { Prop: []Property{{ XMLName: xml.Name{Space: "http://ns.example.com/boxschema/", Local: "DingALing"}, }, { XMLName: xml.Name{Space: "http://ns.example.com/boxschema/", Local: "Random"}, }}, Status: "HTTP/1.1 403 Forbidden", ResponseDescription: "The user does not have access to the DingALing property.", }}, }}, respdesc: "There has been an access violation error.", wantXML: `` + `` + `` + ` ` + ` http://example.com/foo` + ` ` + ` ` + ` Box type A` + ` J.J. Johnson` + ` ` + ` HTTP/1.1 200 OK` + ` ` + ` ` + ` ` + ` ` + ` ` + ` ` + ` HTTP/1.1 403 Forbidden` + ` The user does not have access to the DingALing property.` + ` ` + ` ` + ` There has been an access violation error.` + ``, wantCode: StatusMulti, }, { desc: "no response written", // default of http.responseWriter wantCode: http.StatusOK, }, { desc: "no response written (with description)", respdesc: "too bad", // default of http.responseWriter wantCode: http.StatusOK, }, { desc: "empty multistatus with header", writeHeader: true, wantXML: ``, wantCode: StatusMulti, }, { desc: "bad: no href", responses: []response{{ Propstat: []propstat{{ Prop: []Property{{ XMLName: xml.Name{ Space: "http://example.com/", Local: "foo", }, }}, Status: "HTTP/1.1 200 OK", }}, }}, wantErr: errInvalidResponse, // default of http.responseWriter wantCode: http.StatusOK, }, { desc: "bad: multiple hrefs and no status", responses: []response{{ Href: []string{"http://example.com/foo", "http://example.com/bar"}, }}, wantErr: errInvalidResponse, // default of http.responseWriter wantCode: http.StatusOK, }, { desc: "bad: one href and no propstat", responses: []response{{ Href: []string{"http://example.com/foo"}, }}, wantErr: errInvalidResponse, // default of http.responseWriter wantCode: http.StatusOK, }, { desc: "bad: status with one href and propstat", responses: []response{{ Href: []string{"http://example.com/foo"}, Propstat: []propstat{{ Prop: []Property{{ XMLName: xml.Name{ Space: "http://example.com/", Local: "foo", }, }}, Status: "HTTP/1.1 200 OK", }}, Status: "HTTP/1.1 200 OK", }}, wantErr: errInvalidResponse, // default of http.responseWriter wantCode: http.StatusOK, }, { desc: "bad: multiple hrefs and propstat", responses: []response{{ Href: []string{ "http://example.com/foo", "http://example.com/bar", }, Propstat: []propstat{{ Prop: []Property{{ XMLName: xml.Name{ Space: "http://example.com/", Local: "foo", }, }}, Status: "HTTP/1.1 200 OK", }}, }}, wantErr: errInvalidResponse, // default of http.responseWriter wantCode: http.StatusOK, }} n := xmlNormalizer{omitWhitespace: true} loop: for _, tc := range testCases { rec := httptest.NewRecorder() w := multistatusWriter{w: rec, responseDescription: tc.respdesc} if tc.writeHeader { if err := w.writeHeader(); err != nil { t.Errorf("%s: got writeHeader error %v, want nil", tc.desc, err) continue } } for _, r := range tc.responses { if err := w.write(&r); err != nil { if err != tc.wantErr { t.Errorf("%s: got write error %v, want %v", tc.desc, err, tc.wantErr) } continue loop } } if err := w.close(); err != tc.wantErr { t.Errorf("%s: got close error %v, want %v", tc.desc, err, tc.wantErr) continue } if rec.Code != tc.wantCode { t.Errorf("%s: got HTTP status code %d, want %d\n", tc.desc, rec.Code, tc.wantCode) continue } gotXML := rec.Body.String() eq, err := n.equalXML(strings.NewReader(gotXML), strings.NewReader(tc.wantXML)) if err != nil { t.Errorf("%s: equalXML: %v", tc.desc, err) continue } if !eq { t.Errorf("%s: XML body\ngot %s\nwant %s", tc.desc, gotXML, tc.wantXML) } } } func TestReadProppatch(t *testing.T) { ppStr := func(pps []Proppatch) string { var outer []string for _, pp := range pps { var inner []string for _, p := range pp.Props { inner = append(inner, fmt.Sprintf("{XMLName: %q, Lang: %q, InnerXML: %q}", p.XMLName, p.Lang, p.InnerXML)) } outer = append(outer, fmt.Sprintf("{Remove: %t, Props: [%s]}", pp.Remove, strings.Join(inner, ", "))) } return "[" + strings.Join(outer, ", ") + "]" } testCases := []struct { desc string input string wantPP []Proppatch wantStatus int }{{ desc: "proppatch: section 9.2 (with simple property value)", input: `` + `` + `` + ` ` + ` somevalue` + ` ` + ` ` + ` ` + ` ` + ``, wantPP: []Proppatch{{ Props: []Property{{ xml.Name{Space: "http://ns.example.com/z/", Local: "Authors"}, "", []byte(`somevalue`), }}, }, { Remove: true, Props: []Property{{ xml.Name{Space: "http://ns.example.com/z/", Local: "Copyright-Owner"}, "", nil, }}, }}, }, { desc: "proppatch: lang attribute on prop", input: `` + `` + `` + ` ` + ` ` + ` ` + ` ` + ` ` + ``, wantPP: []Proppatch{{ Props: []Property{{ xml.Name{Space: "http://example.com/ns", Local: "foo"}, "en", nil, }}, }}, }, { desc: "bad: remove with value", input: `` + `` + `` + ` ` + ` ` + ` ` + ` Jim Whitehead` + ` ` + ` ` + ` ` + ``, wantStatus: http.StatusBadRequest, }, { desc: "bad: empty propertyupdate", input: `` + `` + ``, wantStatus: http.StatusBadRequest, }, { desc: "bad: empty prop", input: `` + `` + `` + ` ` + ` ` + ` ` + ``, wantStatus: http.StatusBadRequest, }} for _, tc := range testCases { pp, status, err := readProppatch(strings.NewReader(tc.input)) if tc.wantStatus != 0 { if err == nil { t.Errorf("%s: got nil error, want non-nil", tc.desc) continue } } else if err != nil { t.Errorf("%s: %v", tc.desc, err) continue } if status != tc.wantStatus { t.Errorf("%s: got status %d, want %d", tc.desc, status, tc.wantStatus) continue } if !reflect.DeepEqual(pp, tc.wantPP) || status != tc.wantStatus { t.Errorf("%s: proppatch\ngot %v\nwant %v", tc.desc, ppStr(pp), ppStr(tc.wantPP)) } } } func TestUnmarshalXMLValue(t *testing.T) { testCases := []struct { desc string input string wantVal string }{{ desc: "simple char data", input: "foo", wantVal: "foo", }, { desc: "empty element", input: "", wantVal: "", }, { desc: "preserve namespace", input: ``, wantVal: ``, }, { desc: "preserve root element namespace", input: ``, wantVal: ``, }, { desc: "preserve whitespace", input: " \t ", wantVal: " \t ", }, { desc: "preserve mixed content", input: ` a `, wantVal: ` a `, }, { desc: "section 9.2", input: `` + `` + ` Jim Whitehead` + ` Roy Fielding` + ``, wantVal: `` + ` Jim Whitehead` + ` Roy Fielding`, }, { desc: "section 4.3.1 (mixed content)", input: `` + `` + ` Jane Doe` + ` ` + ` mailto:jane.doe@example.com` + ` http://www.example.com` + ` ` + ` Jane has been working way too long on the` + ` long-awaited revision of ]]>.` + ` ` + ``, wantVal: `` + ` Jane Doe` + ` ` + ` mailto:jane.doe@example.com` + ` http://www.example.com` + ` ` + ` Jane has been working way too long on the` + ` long-awaited revision of <RFC2518>.` + ` `, }} var n xmlNormalizer for _, tc := range testCases { d := xml.NewDecoder(strings.NewReader(tc.input)) var v xmlValue if err := d.Decode(&v); err != nil { t.Errorf("%s: got error %v, want nil", tc.desc, err) continue } eq, err := n.equalXML(bytes.NewReader(v), strings.NewReader(tc.wantVal)) if err != nil { t.Errorf("%s: equalXML: %v", tc.desc, err) continue } if !eq { t.Errorf("%s:\ngot %s\nwant %s", tc.desc, string(v), tc.wantVal) } } } // xmlNormalizer normalizes XML. type xmlNormalizer struct { // omitWhitespace instructs to ignore whitespace between element tags. omitWhitespace bool // omitComments instructs to ignore XML comments. omitComments bool } // normalize writes the normalized XML content of r to w. It applies the // following rules // // * Rename namespace prefixes according to an internal heuristic. // * Remove unnecessary namespace declarations. // * Sort attributes in XML start elements in lexical order of their // fully qualified name. // * Remove XML directives and processing instructions. // * Remove CDATA between XML tags that only contains whitespace, if // instructed to do so. // * Remove comments, if instructed to do so. // func (n *xmlNormalizer) normalize(w io.Writer, r io.Reader) error { d := xml.NewDecoder(r) e := xml.NewEncoder(w) for { t, err := d.Token() if err != nil { if t == nil && err == io.EOF { break } return err } switch val := t.(type) { case xml.Directive, xml.ProcInst: continue case xml.Comment: if n.omitComments { continue } case xml.CharData: if n.omitWhitespace && len(bytes.TrimSpace(val)) == 0 { continue } case xml.StartElement: start, _ := xml.CopyToken(val).(xml.StartElement) attr := start.Attr[:0] for _, a := range start.Attr { if a.Name.Space == "xmlns" || a.Name.Local == "xmlns" { continue } attr = append(attr, a) } sort.Sort(byName(attr)) start.Attr = attr t = start } err = e.EncodeToken(t) if err != nil { return err } } return e.Flush() } // equalXML tests for equality of the normalized XML contents of a and b. func (n *xmlNormalizer) equalXML(a, b io.Reader) (bool, error) { var buf bytes.Buffer if err := n.normalize(&buf, a); err != nil { return false, err } normA := buf.String() buf.Reset() if err := n.normalize(&buf, b); err != nil { return false, err } normB := buf.String() return normA == normB, nil } type byName []xml.Attr func (a byName) Len() int { return len(a) } func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byName) Less(i, j int) bool { if a[i].Name.Space != a[j].Name.Space { return a[i].Name.Space < a[j].Name.Space } return a[i].Name.Local < a[j].Name.Local } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/websocket/000077500000000000000000000000001264464372400224265ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/websocket/client.go000066400000000000000000000051051264464372400242340ustar00rootroot00000000000000// 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/http" "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 } config.Header = http.Header(make(map[string][]string)) 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) err = hybiClientHandshake(config, br, bw) if err != nil { return } buf := bufio.NewReadWriter(br, bw) ws = newHybiClientConn(config, buf, rwc) return } // Dial opens a new client connection to a WebSocket. func Dial(url_, protocol, origin string) (ws *Conn, err error) { config, err := NewConfig(url_, origin) if err != nil { return nil, err } if protocol != "" { config.Protocol = []string{protocol} } return DialConfig(config) } var portMap = map[string]string{ "ws": "80", "wss": "443", } func parseAuthority(location *url.URL) string { if _, ok := portMap[location.Scheme]; ok { if _, _, err := net.SplitHostPort(location.Host); err != nil { return net.JoinHostPort(location.Host, portMap[location.Scheme]) } } return location.Host } // 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", parseAuthority(config.Location)) case "wss": client, err = tls.Dial("tcp", parseAuthority(config.Location), config.TlsConfig) default: err = ErrBadScheme } if err != nil { goto Error } ws, err = NewClient(config, client) if err != nil { client.Close() goto Error } return Error: return nil, &DialError{config, err} } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/websocket/exampledial_test.go000066400000000000000000000012511264464372400263000ustar00rootroot00000000000000// Copyright 2012 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_test import ( "fmt" "log" "golang.org/x/net/websocket" ) // This example demonstrates a trivial client. func ExampleDial() { origin := "http://localhost/" url := "ws://localhost:12345/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) var n int if n, err = ws.Read(msg); err != nil { log.Fatal(err) } fmt.Printf("Received: %s.\n", msg[:n]) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/websocket/examplehandler_test.go000066400000000000000000000011071264464372400270040ustar00rootroot00000000000000// Copyright 2012 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_test import ( "io" "net/http" "golang.org/x/net/websocket" ) // Echo the data received on the WebSocket. func EchoServer(ws *websocket.Conn) { io.Copy(ws, ws) } // This example demonstrates a trivial echo server. func ExampleHandler() { http.Handle("/echo", websocket.Handler(EchoServer)) err := http.ListenAndServe(":12345", nil) if err != nil { panic("ListenAndServe: " + err.Error()) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/websocket/hybi.go000066400000000000000000000372041264464372400237160ustar00rootroot00000000000000// 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"} handshakeHeader = map[string]bool{ "Host": true, "Upgrade": true, "Connection": true, "Sec-Websocket-Key": true, "Sec-Websocket-Origin": true, "Sec-Websocket-Version": true, "Sec-Websocket-Protocol": true, "Sec-Websocket-Accept": true, } ) // 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 Framing 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 } if lengthFields == 8 && i == 0 { // MSB must be zero when 7+64 bits b &= 0x7f } 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) data := make([]byte, length) for i := range data { data[i] = 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) (frameReader, 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, PongFrame: b := make([]byte, maxControlFramePayloadLength) n, err := io.ReadFull(frame, b) if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { return nil, err } io.Copy(ioutil.Discard, frame) if frame.PayloadType() == PingFrame { if _, err := handler.WritePong(b[:n]); err != nil { return nil, err } } return nil, nil } 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 } // generateNonce generates 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 } // removeZone removes IPv6 zone identifer from host. // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080" func removeZone(host string) string { if !strings.HasPrefix(host, "[") { return host } i := strings.LastIndex(host, "]") if i < 0 { return host } j := strings.LastIndex(host[:i], "%") if j < 0 { return host } return host[:j] + host[i:] } // 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 } // Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17 func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) { bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") // According to RFC 6874, an HTTP client, proxy, or other // intermediary must remove any IPv6 zone identifier attached // to an outgoing URI. bw.WriteString("Host: " + removeZone(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") bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n") if config.Version != ProtocolVersionHybi13 { return ErrBadProtocolVersion } 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 Sec-WebSocket-Extensions. err = config.Header.WriteSubset(bw, handshakeHeader) if err != nil { return err } 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") switch version { case "13": c.Version = ProtocolVersionHybi13 default: return http.StatusBadRequest, ErrBadWebSocketVersion } 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")) if 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 } // Origin parses the Origin header in req. // If the Origin header is not set, it returns nil and nil. func Origin(config *Config, req *http.Request) (*url.URL, error) { var origin string switch config.Version { case ProtocolVersionHybi13: origin = req.Header.Get("Origin") } if origin == "" { return nil, nil } return url.ParseRequestURI(origin) } func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) { if len(c.Protocol) > 0 { if len(c.Protocol) != 1 { // You need choose a Protocol in Handshake func in Server. 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): send Sec-WebSocket-Extensions. if c.Header != nil { err := c.Header.WriteSubset(buf, handshakeHeader) if err != nil { return err } } 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) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/websocket/hybi_test.go000066400000000000000000000443041264464372400247540ustar00rootroot00000000000000// 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) { type test struct { url, host string } tests := []test{ {"ws://server.example.com/chat", "server.example.com"}, {"ws://127.0.0.1/chat", "127.0.0.1"}, } if _, err := url.ParseRequestURI("http://[fe80::1%25lo0]"); err == nil { tests = append(tests, test{"ws://[fe80::1%25lo0]/chat", "[fe80::1]"}) } for _, tt := range tests { var b bytes.Buffer 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 var config Config config.Location, err = url.ParseRequestURI(tt.url) 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==", } if err := hybiClientHandshake(&config, br, bw); err != nil { t.Fatal("handshake", err) } req, err := http.ReadRequest(bufio.NewReader(&b)) if err != nil { t.Fatal("read request", err) } if req.Method != "GET" { t.Errorf("request method expected GET, but got %s", req.Method) } if req.URL.Path != "/chat" { t.Errorf("request path expected /chat, but got %s", req.URL.Path) } if req.Proto != "HTTP/1.1" { t.Errorf("request proto expected HTTP/1.1, but got %s", req.Proto) } if req.Host != tt.host { t.Errorf("request host expected %s, but got %s", tt.host, 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("%s expected %s, but got %v", k, v, req.Header.Get(k)) } } } } func TestHybiClientHandshakeWithHeader(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.Header = http.Header(make(map[string][]string)) config.Header.Add("User-Agent", "test") 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), "User-Agent": "test", } 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) } expectedProtocols := []string{"chat", "superchat"} if fmt.Sprintf("%v", config.Protocol) != fmt.Sprintf("%v", expectedProtocols) { t.Errorf("protocol expected %q but got %q", expectedProtocols, config.Protocol) } b := bytes.NewBuffer([]byte{}) bw := bufio.NewWriter(b) config.Protocol = config.Protocol[:1] 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 TestHybiServerHandshakeNoSubProtocol(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-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) } if len(config.Protocol) != 0 { t.Errorf("len(config.Protocol) expected 0, but got %q", len(config.Protocol)) } 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 Switching Protocols", "Upgrade: websocket", "Connection: Upgrade", "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", "", ""}, "\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 && err != io.EOF { 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) { payload := []byte("hello") frameHeader := &hybiFrameHeader{Fin: true, OpCode: PingFrame} testHybiFrame(t, []byte{0x89, 0x05}, payload, payload, frameHeader) frameHeader = &hybiFrameHeader{Fin: true, OpCode: PingFrame} testHybiFrame(t, []byte{0x89, 0x00}, nil, nil, frameHeader) frameHeader = &hybiFrameHeader{Fin: true, OpCode: PongFrame} testHybiFrame(t, []byte{0x8A, 0x05}, payload, payload, frameHeader) frameHeader = &hybiFrameHeader{Fin: true, OpCode: PongFrame} testHybiFrame(t, []byte{0x8A, 0x00}, nil, nil, 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()) } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/websocket/server.go000066400000000000000000000066021264464372400242670ustar00rootroot00000000000000// 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, config *Config, handshake func(*Config, *http.Request) error) (conn *Conn, err error) { 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 { 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 } if handshake != nil { err = handshake(config, req) if err != nil { code = http.StatusForbidden fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code)) buf.WriteString("\r\n") buf.Flush() return } } 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 } // Server represents a server of a WebSocket. type Server struct { // Config is a WebSocket configuration for new WebSocket connection. Config // Handshake is an optional function in WebSocket handshake. // For example, you can check, or don't check Origin header. // Another example, you can select config.Protocol. Handshake func(*Config, *http.Request) error // Handler handles a WebSocket connection. Handler } // ServeHTTP implements the http.Handler interface for a WebSocket func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { s.serveWebSocket(w, req) } func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) { rwc, buf, err := w.(http.Hijacker).Hijack() if err != nil { panic("Hijack failed: " + err.Error()) } // 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, &s.Config, s.Handshake) if err != nil { return } if conn == nil { panic("unexpected nil conn") } s.Handler(conn) } // Handler is a simple interface to a WebSocket browser client. // It checks if Origin header is valid URL by default. // You might want to verify websocket.Conn.Config().Origin in the func. // If you use Server instead of Handler, you could call websocket.Origin and // check the origin in your Handshake func. So, if you want to accept // non-browser clients, which do not send an Origin header, set a // Server.Handshake that does not check the origin. type Handler func(*Conn) func checkOrigin(config *Config, req *http.Request) (err error) { config.Origin, err = Origin(config, req) if err == nil && config.Origin == nil { return fmt.Errorf("null origin") } return err } // ServeHTTP implements the http.Handler interface for a WebSocket func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { s := Server{Handler: h, Handshake: checkOrigin} s.serveWebSocket(w, req) } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/websocket/websocket.go000066400000000000000000000245541264464372400247550ustar00rootroot00000000000000// 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 // as specified in RFC 6455. package websocket // import "golang.org/x/net/websocket" import ( "bufio" "crypto/tls" "encoding/json" "errors" "io" "io/ioutil" "net" "net/http" "net/url" "sync" "time" ) const ( ProtocolVersionHybi13 = 13 ProtocolVersionHybi = ProtocolVersionHybi13 SupportedProtocolVersion = "13" ContinuationFrame = 0 TextFrame = 1 BinaryFrame = 2 CloseFrame = 8 PingFrame = 9 PongFrame = 10 UnknownFrame = 255 ) // ProtocolError represents 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 // Additional header fields to be sent in WebSocket opening handshake. Header http.Header 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 payload 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) err1 := ws.rwc.Close() if err != nil { return err } return err1 } 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) { data, payloadType, err := cd.Marshal(v) if err != nil { return err } ws.wio.Lock() defer ws.wio.Unlock() w, err := ws.frameWriterFactory.NewFrameWriter(payloadType) if err != nil { return err } _, 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. Trivial 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} golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/websocket/websocket_test.go000066400000000000000000000304421264464372400260050ustar00rootroot00000000000000// 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" "reflect" "runtime" "strings" "sync" "testing" "time" ) var serverAddr string var once sync.Once func echoServer(ws *Conn) { defer ws.Close() io.Copy(ws, ws) } type Count struct { S string N int } func countServer(ws *Conn) { defer ws.Close() 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 } } } type testCtrlAndDataHandler struct { hybiFrameHandler } func (h *testCtrlAndDataHandler) WritePing(b []byte) (int, error) { h.hybiFrameHandler.conn.wio.Lock() defer h.hybiFrameHandler.conn.wio.Unlock() w, err := h.hybiFrameHandler.conn.frameWriterFactory.NewFrameWriter(PingFrame) if err != nil { return 0, err } n, err := w.Write(b) w.Close() return n, err } func ctrlAndDataServer(ws *Conn) { defer ws.Close() h := &testCtrlAndDataHandler{hybiFrameHandler: hybiFrameHandler{conn: ws}} ws.frameHandler = h go func() { for i := 0; ; i++ { var b []byte if i%2 != 0 { // with or without payload b = []byte(fmt.Sprintf("#%d-CONTROL-FRAME-FROM-SERVER", i)) } if _, err := h.WritePing(b); err != nil { break } if _, err := h.WritePong(b); err != nil { // unsolicited pong break } time.Sleep(10 * time.Millisecond) } }() b := make([]byte, 128) for { n, err := ws.Read(b) if err != nil { break } if _, err := ws.Write(b[:n]); err != nil { break } } } func subProtocolHandshake(config *Config, req *http.Request) error { for _, proto := range config.Protocol { if proto == "chat" { config.Protocol = []string{proto} return nil } } return ErrBadWebSocketProtocol } func subProtoServer(ws *Conn) { for _, proto := range ws.Config().Protocol { io.WriteString(ws, proto) } } func startServer() { http.Handle("/echo", Handler(echoServer)) http.Handle("/count", Handler(countServer)) http.Handle("/ctrldata", Handler(ctrlAndDataServer)) subproto := Server{ Handshake: subProtocolHandshake, Handler: Handler(subProtoServer), } http.Handle("/subproto", subproto) 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, subproto []string) (string, error) { once.Do(startServer) client, err := net.Dial("tcp", serverAddr) if err != nil { t.Fatal("dialing", err) } config := newConfig(t, "/subproto") config.Protocol = subproto ws, err := NewClient(config, client) if err != nil { return "", err } msg := make([]byte, 16) n, err := ws.Read(msg) if err != nil { return "", err } ws.Close() return string(msg[:n]), nil } func TestWithProtocol(t *testing.T) { proto, err := testWithProtocol(t, []string{"chat"}) if err != nil { t.Errorf("SubProto: unexpected error: %v", err) } if proto != "chat" { t.Errorf("SubProto: expected %q, got %q", "chat", proto) } } func TestWithTwoProtocol(t *testing.T) { proto, err := testWithProtocol(t, []string{"test", "chat"}) if err != nil { t.Errorf("SubProto: unexpected error: %v", err) } if proto != "chat" { t.Errorf("SubProto: expected %q, got %q", "chat", proto) } } func TestWithBadProtocol(t *testing.T) { _, err := testWithProtocol(t, []string{"test"}) if err != ErrBadStatus { t.Errorf("SubProto: expected %v, got %v", ErrBadStatus, err) } } 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 response 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 TestDialConfigBadVersion(t *testing.T) { once.Do(startServer) config := newConfig(t, "/echo") config.Version = 1234 _, err := DialConfig(config) if dialerr, ok := err.(*DialError); ok { if dialerr.Err != ErrBadProtocolVersion { t.Errorf("dial expected err %q but got %q", ErrBadProtocolVersion, dialerr.Err) } } } 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() } var parseAuthorityTests = []struct { in *url.URL out string }{ { &url.URL{ Scheme: "ws", Host: "www.google.com", }, "www.google.com:80", }, { &url.URL{ Scheme: "wss", Host: "www.google.com", }, "www.google.com:443", }, { &url.URL{ Scheme: "ws", Host: "www.google.com:80", }, "www.google.com:80", }, { &url.URL{ Scheme: "wss", Host: "www.google.com:443", }, "www.google.com:443", }, // some invalid ones for parseAuthority. parseAuthority doesn't // concern itself with the scheme unless it actually knows about it { &url.URL{ Scheme: "http", Host: "www.google.com", }, "www.google.com", }, { &url.URL{ Scheme: "http", Host: "www.google.com:80", }, "www.google.com:80", }, { &url.URL{ Scheme: "asdf", Host: "127.0.0.1", }, "127.0.0.1", }, { &url.URL{ Scheme: "asdf", Host: "www.google.com", }, "www.google.com", }, } func TestParseAuthority(t *testing.T) { for _, tt := range parseAuthorityTests { out := parseAuthority(tt.in) if out != tt.out { t.Errorf("got %v; want %v", out, tt.out) } } } type closerConn struct { net.Conn closed int // count of the number of times Close was called } func (c *closerConn) Close() error { c.closed++ return c.Conn.Close() } func TestClose(t *testing.T) { if runtime.GOOS == "plan9" { t.Skip("see golang.org/issue/11454") } once.Do(startServer) conn, err := net.Dial("tcp", serverAddr) if err != nil { t.Fatal("dialing", err) } cc := closerConn{Conn: conn} client, err := NewClient(newConfig(t, "/echo"), &cc) if err != nil { t.Fatalf("WebSocket handshake: %v", err) } // set the deadline to ten minutes ago, which will have expired by the time // client.Close sends the close status frame. conn.SetDeadline(time.Now().Add(-10 * time.Minute)) if err := client.Close(); err == nil { t.Errorf("ws.Close(): expected error, got %v", err) } if cc.closed < 1 { t.Fatalf("ws.Close(): expected underlying ws.rwc.Close to be called > 0 times, got: %v", cc.closed) } } var originTests = []struct { req *http.Request origin *url.URL }{ { req: &http.Request{ Header: http.Header{ "Origin": []string{"http://www.example.com"}, }, }, origin: &url.URL{ Scheme: "http", Host: "www.example.com", }, }, { req: &http.Request{}, }, } func TestOrigin(t *testing.T) { conf := newConfig(t, "/echo") conf.Version = ProtocolVersionHybi13 for i, tt := range originTests { origin, err := Origin(conf, tt.req) if err != nil { t.Error(err) continue } if !reflect.DeepEqual(origin, tt.origin) { t.Errorf("#%d: got origin %v; want %v", i, origin, tt.origin) continue } } } func TestCtrlAndData(t *testing.T) { once.Do(startServer) c, err := net.Dial("tcp", serverAddr) if err != nil { t.Fatal(err) } ws, err := NewClient(newConfig(t, "/ctrldata"), c) if err != nil { t.Fatal(err) } defer ws.Close() h := &testCtrlAndDataHandler{hybiFrameHandler: hybiFrameHandler{conn: ws}} ws.frameHandler = h b := make([]byte, 128) for i := 0; i < 2; i++ { data := []byte(fmt.Sprintf("#%d-DATA-FRAME-FROM-CLIENT", i)) if _, err := ws.Write(data); err != nil { t.Fatalf("#%d: %v", i, err) } var ctrl []byte if i%2 != 0 { // with or without payload ctrl = []byte(fmt.Sprintf("#%d-CONTROL-FRAME-FROM-CLIENT", i)) } if _, err := h.WritePing(ctrl); err != nil { t.Fatalf("#%d: %v", i, err) } n, err := ws.Read(b) if err != nil { t.Fatalf("#%d: %v", i, err) } if !bytes.Equal(b[:n], data) { t.Fatalf("#%d: got %v; want %v", i, b[:n], data) } } } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/xsrftoken/000077500000000000000000000000001264464372400224635ustar00rootroot00000000000000golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/xsrftoken/xsrf.go000066400000000000000000000055621264464372400240040ustar00rootroot00000000000000// Copyright 2012 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 xsrftoken provides methods for generating and validating secure XSRF tokens. package xsrftoken // import "golang.org/x/net/xsrftoken" import ( "crypto/hmac" "crypto/sha1" "crypto/subtle" "encoding/base64" "fmt" "strconv" "strings" "time" ) // Timeout is the duration for which XSRF tokens are valid. // It is exported so clients may set cookie timeouts that match generated tokens. const Timeout = 24 * time.Hour // clean sanitizes a string for inclusion in a token by replacing all ":"s. func clean(s string) string { return strings.Replace(s, ":", "_", -1) } // Generate returns a URL-safe secure XSRF token that expires in 24 hours. // // key is a secret key for your application. // userID is a unique identifier for the user. // actionID is the action the user is taking (e.g. POSTing to a particular path). func Generate(key, userID, actionID string) string { return generateTokenAtTime(key, userID, actionID, time.Now()) } // generateTokenAtTime is like Generate, but returns a token that expires 24 hours from now. func generateTokenAtTime(key, userID, actionID string, now time.Time) string { // Round time up and convert to milliseconds. milliTime := (now.UnixNano() + 1e6 - 1) / 1e6 h := hmac.New(sha1.New, []byte(key)) fmt.Fprintf(h, "%s:%s:%d", clean(userID), clean(actionID), milliTime) // Get the padded base64 string then removing the padding. tok := string(h.Sum(nil)) tok = base64.URLEncoding.EncodeToString([]byte(tok)) tok = strings.TrimRight(tok, "=") return fmt.Sprintf("%s:%d", tok, milliTime) } // Valid reports whether a token is a valid, unexpired token returned by Generate. func Valid(token, key, userID, actionID string) bool { return validTokenAtTime(token, key, userID, actionID, time.Now()) } // validTokenAtTime reports whether a token is valid at the given time. func validTokenAtTime(token, key, userID, actionID string, now time.Time) bool { // Extract the issue time of the token. sep := strings.LastIndex(token, ":") if sep < 0 { return false } millis, err := strconv.ParseInt(token[sep+1:], 10, 64) if err != nil { return false } issueTime := time.Unix(0, millis*1e6) // Check that the token is not expired. if now.Sub(issueTime) >= Timeout { return false } // Check that the token is not from the future. // Allow 1 minute grace period in case the token is being verified on a // machine whose clock is behind the machine that issued the token. if issueTime.After(now.Add(1 * time.Minute)) { return false } expected := generateTokenAtTime(key, userID, actionID, issueTime) // Check that the token matches the expected value. // Use constant time comparison to avoid timing attacks. return subtle.ConstantTimeCompare([]byte(token), []byte(expected)) == 1 } golang-golang-x-net-dev-0.0+git20160110.4fd4a9f/xsrftoken/xsrf_test.go000066400000000000000000000051561264464372400250420ustar00rootroot00000000000000// Copyright 2012 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 xsrftoken import ( "encoding/base64" "testing" "time" ) const ( key = "quay" userID = "12345678" actionID = "POST /form" ) var ( now = time.Now() oneMinuteFromNow = now.Add(1 * time.Minute) ) func TestValidToken(t *testing.T) { tok := generateTokenAtTime(key, userID, actionID, now) if !validTokenAtTime(tok, key, userID, actionID, oneMinuteFromNow) { t.Error("One second later: Expected token to be valid") } if !validTokenAtTime(tok, key, userID, actionID, now.Add(Timeout-1*time.Nanosecond)) { t.Error("Just before timeout: Expected token to be valid") } if !validTokenAtTime(tok, key, userID, actionID, now.Add(-1*time.Minute+1*time.Millisecond)) { t.Error("One minute in the past: Expected token to be valid") } } // TestSeparatorReplacement tests that separators are being correctly substituted func TestSeparatorReplacement(t *testing.T) { tok := generateTokenAtTime("foo:bar", "baz", "wah", now) tok2 := generateTokenAtTime("foo", "bar:baz", "wah", now) if tok == tok2 { t.Errorf("Expected generated tokens to be different") } } func TestInvalidToken(t *testing.T) { invalidTokenTests := []struct { name, key, userID, actionID string t time.Time }{ {"Bad key", "foobar", userID, actionID, oneMinuteFromNow}, {"Bad userID", key, "foobar", actionID, oneMinuteFromNow}, {"Bad actionID", key, userID, "foobar", oneMinuteFromNow}, {"Expired", key, userID, actionID, now.Add(Timeout + 1*time.Millisecond)}, {"More than 1 minute from the future", key, userID, actionID, now.Add(-1*time.Nanosecond - 1*time.Minute)}, } tok := generateTokenAtTime(key, userID, actionID, now) for _, itt := range invalidTokenTests { if validTokenAtTime(tok, itt.key, itt.userID, itt.actionID, itt.t) { t.Errorf("%v: Expected token to be invalid", itt.name) } } } // TestValidateBadData primarily tests that no unexpected panics are triggered // during parsing func TestValidateBadData(t *testing.T) { badDataTests := []struct { name, tok string }{ {"Invalid Base64", "ASDab24(@)$*=="}, {"No delimiter", base64.URLEncoding.EncodeToString([]byte("foobar12345678"))}, {"Invalid time", base64.URLEncoding.EncodeToString([]byte("foobar:foobar"))}, {"Wrong length", "1234" + generateTokenAtTime(key, userID, actionID, now)}, } for _, bdt := range badDataTests { if validTokenAtTime(bdt.tok, key, userID, actionID, oneMinuteFromNow) { t.Errorf("%v: Expected token to be invalid", bdt.name) } } }