<commit_before>package forge

import (
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"

	"github.com/brettlangdon/forge/token"
)

type Parser struct {
	settings    *Section
	scanner     *Scanner
	cur_tok     token.Token
	cur_section *Section
	previous    []*Section
}

func NewParser(reader io.Reader) *Parser {
	settings := NewSection()
	return &Parser{
		scanner:     NewScanner(reader),
		settings:    settings,
		cur_section: settings,
		previous:    make([]*Section, 0),
	}
}

func (this *Parser) syntaxError(msg string) error {
	msg = fmt.Sprintf(
		"Syntax error line <%d> column <%d>: %s",
		this.cur_tok.Line,
		this.cur_tok.Column,
		msg,
	)
	return errors.New(msg)
}

func (this *Parser) readToken() token.Token {
	this.cur_tok = this.scanner.NextToken()
	return this.cur_tok
}

func (this *Parser) parseReference(starting_section *Section, period bool) (Value, error) {
	name := ""
	if period == false {
		name = this.cur_tok.Literal
	}
	for {
		this.readToken()
		if this.cur_tok.ID == token.PERIOD && period == false {
			period = true
		} else if period && this.cur_tok.ID == token.IDENTIFIER {
			if len(name) > 0 {
				name += "."
			}
			name += this.cur_tok.Literal
			period = false
		} else if this.cur_tok.ID == token.SEMICOLON {
			break
		} else {
			msg := fmt.Sprintf("expected ';' instead found '%s'", this.cur_tok.Literal)
			return nil, this.syntaxError(msg)
		}
	}
	if len(name) == 0 {
		return nil, this.syntaxError(
			fmt.Sprintf("expected IDENTIFIER instead found %s", this.cur_tok.Literal),
		)
	}

	if period {
		return nil, this.syntaxError(fmt.Sprintf("expected IDENTIFIER after PERIOD"))
	}

	value, err := starting_section.Resolve(name)
	if err != nil {
		err = errors.New("Reference error, " + err.Error())
	}
	return value, nil
}

func (this *Parser) parseSetting(name string) error {
	var value Value
	this.readToken()

	read_next := true
	switch this.cur_tok.ID {
	case token.STRING:
		value = NewString(this.cur_tok.Literal)
	case token.BOOLEAN:
		bool_val, err := strconv.ParseBool(this.cur_tok.Literal)
		if err != nil {
			return nil
		}
		value = NewBoolean(bool_val)
	case token.NULL:
		value = NewNull()
	case token.INTEGER:
		int_val, err := strconv.ParseInt(this.cur_tok.Literal, 10, 64)
		if err != nil {
			return err
		}
		value = NewInteger(int_val)
	case token.FLOAT:
		float_val, err := strconv.ParseFloat(this.cur_tok.Literal, 64)
		if err != nil {
			return err
		}
		value = NewFloat(float_val)
	case token.PERIOD:
		reference, err := this.parseReference(this.cur_section, true)
		if err != nil {
			return err
		}
		value = reference
		read_next = false
	case token.IDENTIFIER:
		reference, err := this.parseReference(this.settings, false)
		if err != nil {
			return err
		}
		value = reference
		read_next = false
	default:
		return this.syntaxError(
			fmt.Sprintf("expected STRING, INTEGER, FLOAT, BOOLEAN or IDENTIFIER, instead found %s", this.cur_tok.ID),
		)
	}

	if read_next {
		this.readToken()
	}
	if this.cur_tok.ID != token.SEMICOLON {
		msg := fmt.Sprintf("expected ';' instead found '%s'", this.cur_tok.Literal)
		return this.syntaxError(msg)
	}
	this.readToken()

	this.cur_section.Set(name, value)
	return nil
}

func (this *Parser) parseInclude() error {
	if this.cur_tok.ID != token.STRING {
		msg := fmt.Sprintf("expected STRING instead found '%s'", this.cur_tok.ID)
		return this.syntaxError(msg)
	}
	pattern := this.cur_tok.Literal

	this.readToken()
	if this.cur_tok.ID != token.SEMICOLON {
		msg := fmt.Sprintf("expected ';' instead found '%s'", this.cur_tok.Literal)
		return this.syntaxError(msg)
	}

	filenames, err := filepath.Glob(pattern)
	if err != nil {
		return err
	}
	old_scanner := this.scanner
	for _, filename := range filenames {
		reader, err := os.Open(filename)
		if err != nil {
			return err
		}
		// this.cur_section.AddInclude(filename)
		this.scanner = NewScanner(reader)
		this.parse()
	}
	this.scanner = old_scanner
	this.readToken()
	return nil
}

func (this *Parser) parseSection(name string) error {
	section := this.cur_section.AddSection(name)
	this.previous = append(this.previous, this.cur_section)
	this.cur_section = section
	return nil
}

func (this *Parser) endSection() error {
	if len(this.previous) == 0 {
		return this.syntaxError("unexpected section end '}'")
	}

	p_len := len(this.previous)
	previous := this.previous[p_len-1]
	this.previous = this.previous[0 : p_len-1]
	this.cur_section = previous
	return nil
}

func (this *Parser) GetSettings() *Section {
	return this.settings
}

func (this *Parser) parse() error {
	this.readToken()
	for {
		if this.cur_tok.ID == token.EOF {
			break
		}
		tok := this.cur_tok
		this.readToken()
		switch tok.ID {
		case token.COMMENT:
			// this.cur_section.AddComment(tok.Literal)
		case token.INCLUDE:
			this.parseInclude()
		case token.IDENTIFIER:
			if this.cur_tok.ID == token.LBRACKET {
				err := this.parseSection(tok.Literal)
				if err != nil {
					return err
				}
				this.readToken()
			} else if this.cur_tok.ID == token.EQUAL {
				err := this.parseSetting(tok.Literal)
				if err != nil {
					return err
				}
			}
		case token.RBRACKET:
			err := this.endSection()
			if err != nil {
				return err
			}
		default:
			return this.syntaxError(fmt.Sprintf("unexpected token %s", tok))
		}
	}
	return nil
}

func (this *Parser) Parse() error {
	err := this.parse()
	if err != nil {
		return err
	}

	if len(this.previous) > 0 {
		return this.syntaxError("expected end of section, instead found EOF")
	}

	return nil
}
<commit_msg>remove underscore names in parser<commit_after>package forge

import (
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"

	"github.com/brettlangdon/forge/token"
)

type Parser struct {
	settings   *Section
	scanner    *Scanner
	curTok     token.Token
	curSection *Section
	previous   []*Section
}

func NewParser(reader io.Reader) *Parser {
	settings := NewSection()
	return &Parser{
		scanner:    NewScanner(reader),
		settings:   settings,
		curSection: settings,
		previous:   make([]*Section, 0),
	}
}

func (this *Parser) syntaxError(msg string) error {
	msg = fmt.Sprintf(
		"Syntax error line <%d> column <%d>: %s",
		this.curTok.Line,
		this.curTok.Column,
		msg,
	)
	return errors.New(msg)
}

func (this *Parser) readToken() token.Token {
	this.curTok = this.scanner.NextToken()
	return this.curTok
}

func (this *Parser) parseReference(startingSection *Section, period bool) (Value, error) {
	name := ""
	if period == false {
		name = this.curTok.Literal
	}
	for {
		this.readToken()
		if this.curTok.ID == token.PERIOD && period == false {
			period = true
		} else if period && this.curTok.ID == token.IDENTIFIER {
			if len(name) > 0 {
				name += "."
			}
			name += this.curTok.Literal
			period = false
		} else if this.curTok.ID == token.SEMICOLON {
			break
		} else {
			msg := fmt.Sprintf("expected ';' instead found '%s'", this.curTok.Literal)
			return nil, this.syntaxError(msg)
		}
	}
	if len(name) == 0 {
		return nil, this.syntaxError(
			fmt.Sprintf("expected IDENTIFIER instead found %s", this.curTok.Literal),
		)
	}

	if period {
		return nil, this.syntaxError(fmt.Sprintf("expected IDENTIFIER after PERIOD"))
	}

	value, err := startingSection.Resolve(name)
	if err != nil {
		err = errors.New("Reference error, " + err.Error())
	}
	return value, nil
}

func (this *Parser) parseSetting(name string) error {
	var value Value
	this.readToken()

	read_next := true
	switch this.curTok.ID {
	case token.STRING:
		value = NewString(this.curTok.Literal)
	case token.BOOLEAN:
		boolVal, err := strconv.ParseBool(this.curTok.Literal)
		if err != nil {
			return nil
		}
		value = NewBoolean(boolVal)
	case token.NULL:
		value = NewNull()
	case token.INTEGER:
		intVal, err := strconv.ParseInt(this.curTok.Literal, 10, 64)
		if err != nil {
			return err
		}
		value = NewInteger(intVal)
	case token.FLOAT:
		floatVal, err := strconv.ParseFloat(this.curTok.Literal, 64)
		if err != nil {
			return err
		}
		value = NewFloat(floatVal)
	case token.PERIOD:
		reference, err := this.parseReference(this.curSection, true)
		if err != nil {
			return err
		}
		value = reference
		read_next = false
	case token.IDENTIFIER:
		reference, err := this.parseReference(this.settings, false)
		if err != nil {
			return err
		}
		value = reference
		read_next = false
	default:
		return this.syntaxError(
			fmt.Sprintf("expected STRING, INTEGER, FLOAT, BOOLEAN or IDENTIFIER, instead found %s", this.curTok.ID),
		)
	}

	if read_next {
		this.readToken()
	}
	if this.curTok.ID != token.SEMICOLON {
		msg := fmt.Sprintf("expected ';' instead found '%s'", this.curTok.Literal)
		return this.syntaxError(msg)
	}
	this.readToken()

	this.curSection.Set(name, value)
	return nil
}

func (this *Parser) parseInclude() error {
	if this.curTok.ID != token.STRING {
		msg := fmt.Sprintf("expected STRING instead found '%s'", this.curTok.ID)
		return this.syntaxError(msg)
	}
	pattern := this.curTok.Literal

	this.readToken()
	if this.curTok.ID != token.SEMICOLON {
		msg := fmt.Sprintf("expected ';' instead found '%s'", this.curTok.Literal)
		return this.syntaxError(msg)
	}

	filenames, err := filepath.Glob(pattern)
	if err != nil {
		return err
	}
	oldScanner := this.scanner
	for _, filename := range filenames {
		reader, err := os.Open(filename)
		if err != nil {
			return err
		}
		// this.curSection.AddInclude(filename)
		this.scanner = NewScanner(reader)
		this.parse()
	}
	this.scanner = oldScanner
	this.readToken()
	return nil
}

func (this *Parser) parseSection(name string) error {
	section := this.curSection.AddSection(name)
	this.previous = append(this.previous, this.curSection)
	this.curSection = section
	return nil
}

func (this *Parser) endSection() error {
	if len(this.previous) == 0 {
		return this.syntaxError("unexpected section end '}'")
	}

	pLen := len(this.previous)
	previous := this.previous[pLen-1]
	this.previous = this.previous[0 : pLen-1]
	this.curSection = previous
	return nil
}

func (this *Parser) GetSettings() *Section {
	return this.settings
}

func (this *Parser) parse() error {
	this.readToken()
	for {
		if this.curTok.ID == token.EOF {
			break
		}
		tok := this.curTok
		this.readToken()
		switch tok.ID {
		case token.COMMENT:
			// this.curSection.AddComment(tok.Literal)
		case token.INCLUDE:
			this.parseInclude()
		case token.IDENTIFIER:
			if this.curTok.ID == token.LBRACKET {
				err := this.parseSection(tok.Literal)
				if err != nil {
					return err
				}
				this.readToken()
			} else if this.curTok.ID == token.EQUAL {
				err := this.parseSetting(tok.Literal)
				if err != nil {
					return err
				}
			}
		case token.RBRACKET:
			err := this.endSection()
			if err != nil {
				return err
			}
		default:
			return this.syntaxError(fmt.Sprintf("unexpected token %s", tok))
		}
	}
	return nil
}

func (this *Parser) Parse() error {
	err := this.parse()
	if err != nil {
		return err
	}

	if len(this.previous) > 0 {
		return this.syntaxError("expected end of section, instead found EOF")
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2018 The Go 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 lsp

import (
	"context"
	"fmt"
	"sort"
	"strings"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/span"
	"golang.org/x/tools/internal/telemetry/log"
	"golang.org/x/tools/internal/telemetry/tag"
)

func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
	uri := span.NewURI(params.TextDocument.URI)
	view, err := s.session.ViewOf(uri)
	if err != nil {
		return nil, err
	}
	snapshot := view.Snapshot()
	options := view.Options()
	fh, err := snapshot.GetFile(ctx, uri)
	if err != nil {
		return nil, err
	}
	var candidates []source.CompletionItem
	var surrounding *source.Selection
	switch fh.Identity().Kind {
	case source.Go:
		options.Completion.FullDocumentation = options.HoverKind == source.FullDocumentation
		candidates, surrounding, err = source.Completion(ctx, snapshot, fh, params.Position, options.Completion)
	case source.Mod:
		candidates, surrounding = nil, nil
	}

	if err != nil {
		log.Print(ctx, "no completions found", tag.Of("At", params.Position), tag.Of("Failure", err))
	}
	if candidates == nil {
		return &protocol.CompletionList{
			Items: []protocol.CompletionItem{},
		}, nil
	}
	// We might need to adjust the position to account for the prefix.
	rng, err := surrounding.Range()
	if err != nil {
		return nil, err
	}
	// Sort the candidates by score, then label, since that is not supported by LSP yet.
	sort.SliceStable(candidates, func(i, j int) bool {
		if candidates[i].Score != candidates[j].Score {
			return candidates[i].Score > candidates[j].Score
		}
		return candidates[i].Label < candidates[j].Label
	})

	// When using deep completions/fuzzy matching, report results as incomplete so
	// client fetches updated completions after every key stroke.
	incompleteResults := options.Completion.Deep || options.Completion.FuzzyMatching

	items := toProtocolCompletionItems(candidates, rng, options)

	if incompleteResults && len(items) > 1 {
		for i := range items[1:] {
			// Give all the candidaites the same filterText to trick VSCode
			// into not reordering our candidates. All the candidates will
			// appear to be equally good matches, so VSCode's fuzzy
			// matching/ranking just maintains the natural "sortText"
			// ordering. We can only do this in tandem with
			// "incompleteResults" since otherwise client side filtering is
			// important.
			items[i].FilterText = items[0].FilterText
		}
	}

	return &protocol.CompletionList{
		IsIncomplete: incompleteResults,
		Items:        items,
	}, nil
}

func toProtocolCompletionItems(candidates []source.CompletionItem, rng protocol.Range, options source.Options) []protocol.CompletionItem {
	var (
		items                  = make([]protocol.CompletionItem, 0, len(candidates))
		numDeepCompletionsSeen int
	)
	for i, candidate := range candidates {
		// Limit the number of deep completions to not overwhelm the user in cases
		// with dozens of deep completion matches.
		if candidate.Depth > 0 {
			if !options.Completion.Deep {
				continue
			}
			if numDeepCompletionsSeen >= source.MaxDeepCompletions {
				continue
			}
			numDeepCompletionsSeen++
		}
		insertText := candidate.InsertText
		if options.InsertTextFormat == protocol.SnippetTextFormat {
			insertText = candidate.Snippet()
		}

		// This can happen if the client has snippets disabled but the
		// candidate only supports snippet insertion.
		if insertText == "" {
			continue
		}

		item := protocol.CompletionItem{
			Label:  candidate.Label,
			Detail: candidate.Detail,
			Kind:   candidate.Kind,
			TextEdit: &protocol.TextEdit{
				NewText: insertText,
				Range:   rng,
			},
			InsertTextFormat:    options.InsertTextFormat,
			AdditionalTextEdits: candidate.AdditionalTextEdits,
			// This is a hack so that the client sorts completion results in the order
			// according to their score. This can be removed upon the resolution of
			// https://github.com/Microsoft/language-server-protocol/issues/348.
			SortText: fmt.Sprintf("%05d", i),

			// Trim address operator (VSCode doesn't like weird characters
			// in filterText).
			FilterText: strings.TrimLeft(candidate.InsertText, "&"),

			Preselect:     i == 0,
			Documentation: candidate.Documentation,
		}
		// Trigger signature help for any function or method completion.
		// This is helpful even if a function does not have parameters,
		// since we show return types as well.
		switch item.Kind {
		case protocol.FunctionCompletion, protocol.MethodCompletion:
			item.Command = &protocol.Command{
				Command: "editor.action.triggerParameterHints",
			}
		}
		items = append(items, item)
	}
	return items
}
<commit_msg>internal/lsp: fix completion ordering workaround<commit_after>// Copyright 2018 The Go 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 lsp

import (
	"context"
	"fmt"
	"sort"
	"strings"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/span"
	"golang.org/x/tools/internal/telemetry/log"
	"golang.org/x/tools/internal/telemetry/tag"
)

func (s *Server) completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
	uri := span.NewURI(params.TextDocument.URI)
	view, err := s.session.ViewOf(uri)
	if err != nil {
		return nil, err
	}
	snapshot := view.Snapshot()
	options := view.Options()
	fh, err := snapshot.GetFile(ctx, uri)
	if err != nil {
		return nil, err
	}
	var candidates []source.CompletionItem
	var surrounding *source.Selection
	switch fh.Identity().Kind {
	case source.Go:
		options.Completion.FullDocumentation = options.HoverKind == source.FullDocumentation
		candidates, surrounding, err = source.Completion(ctx, snapshot, fh, params.Position, options.Completion)
	case source.Mod:
		candidates, surrounding = nil, nil
	}

	if err != nil {
		log.Print(ctx, "no completions found", tag.Of("At", params.Position), tag.Of("Failure", err))
	}
	if candidates == nil {
		return &protocol.CompletionList{
			Items: []protocol.CompletionItem{},
		}, nil
	}
	// We might need to adjust the position to account for the prefix.
	rng, err := surrounding.Range()
	if err != nil {
		return nil, err
	}
	// Sort the candidates by score, then label, since that is not supported by LSP yet.
	sort.SliceStable(candidates, func(i, j int) bool {
		if candidates[i].Score != candidates[j].Score {
			return candidates[i].Score > candidates[j].Score
		}
		return candidates[i].Label < candidates[j].Label
	})

	// When using deep completions/fuzzy matching, report results as incomplete so
	// client fetches updated completions after every key stroke.
	incompleteResults := options.Completion.Deep || options.Completion.FuzzyMatching

	items := toProtocolCompletionItems(candidates, rng, options)

	if incompleteResults {
		for i := 1; i < len(items); i++ {
			// Give all the candidates the same filterText to trick VSCode
			// into not reordering our candidates. All the candidates will
			// appear to be equally good matches, so VSCode's fuzzy
			// matching/ranking just maintains the natural "sortText"
			// ordering. We can only do this in tandem with
			// "incompleteResults" since otherwise client side filtering is
			// important.
			items[i].FilterText = items[0].FilterText
		}
	}

	return &protocol.CompletionList{
		IsIncomplete: incompleteResults,
		Items:        items,
	}, nil
}

func toProtocolCompletionItems(candidates []source.CompletionItem, rng protocol.Range, options source.Options) []protocol.CompletionItem {
	var (
		items                  = make([]protocol.CompletionItem, 0, len(candidates))
		numDeepCompletionsSeen int
	)
	for i, candidate := range candidates {
		// Limit the number of deep completions to not overwhelm the user in cases
		// with dozens of deep completion matches.
		if candidate.Depth > 0 {
			if !options.Completion.Deep {
				continue
			}
			if numDeepCompletionsSeen >= source.MaxDeepCompletions {
				continue
			}
			numDeepCompletionsSeen++
		}
		insertText := candidate.InsertText
		if options.InsertTextFormat == protocol.SnippetTextFormat {
			insertText = candidate.Snippet()
		}

		// This can happen if the client has snippets disabled but the
		// candidate only supports snippet insertion.
		if insertText == "" {
			continue
		}

		item := protocol.CompletionItem{
			Label:  candidate.Label,
			Detail: candidate.Detail,
			Kind:   candidate.Kind,
			TextEdit: &protocol.TextEdit{
				NewText: insertText,
				Range:   rng,
			},
			InsertTextFormat:    options.InsertTextFormat,
			AdditionalTextEdits: candidate.AdditionalTextEdits,
			// This is a hack so that the client sorts completion results in the order
			// according to their score. This can be removed upon the resolution of
			// https://github.com/Microsoft/language-server-protocol/issues/348.
			SortText: fmt.Sprintf("%05d", i),

			// Trim address operator (VSCode doesn't like weird characters
			// in filterText).
			FilterText: strings.TrimLeft(candidate.InsertText, "&"),

			Preselect:     i == 0,
			Documentation: candidate.Documentation,
		}
		// Trigger signature help for any function or method completion.
		// This is helpful even if a function does not have parameters,
		// since we show return types as well.
		switch item.Kind {
		case protocol.FunctionCompletion, protocol.MethodCompletion:
			item.Command = &protocol.Command{
				Command: "editor.action.triggerParameterHints",
			}
		}
		items = append(items, item)
	}
	return items
}
<|endoftext|>


<commit_before>// 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 template

import (
	"fmt"
)

// Error describes a problem encountered during template Escaping.
type Error struct {
	// ErrorCode describes the kind of error.
	ErrorCode ErrorCode
	// Name is the name of the template in which the error was encountered.
	Name string
	// Line is the line number of the error in the template source or 0.
	Line int
	// Description is a human-readable description of the problem.
	Description string
}

// ErrorCode is a code for a kind of error.
type ErrorCode int

// We define codes for each error that manifests while escaping templates, but
// escaped templates may also fail at runtime.
//
// Output: "ZgotmplZ"
// Example:
//
//   where {{.X}} evaluates to `javascript:...`
// Discussion:
//   "ZgotmplZ" is a special value that indicates that unsafe content reached a
//   CSS or URL context at runtime. The output of the example will be
//
//   If the data comes from a trusted source, use content types to exempt it
//   from filtering: URL(`javascript:...`).
const (
	// OK indicates the lack of an error.
	OK ErrorCode = iota

	// ErrAmbigContext: "... appears in an ambiguous URL context"
	// Example:
	//
	// Discussion:
	//   {{.X}} is in an ambiguous URL context since, depending on {{.C}},
	//  it may be either a URL suffix or a query parameter.
	//   Moving {{.X}} into the condition removes the ambiguity:
	//
	ErrAmbigContext

	// ErrBadHTML: "expected space, attr name, or end of tag, but got ...",
	//   "... in unquoted attr", "... in attribute name"
	// Example:
	//
	//   <href=foo>
	//   <form na<e=...>
	//   <option selected<
	// Discussion:
	//   This is often due to a typo in an HTML element, but some runes
	//   are banned in tag names, attribute names, and unquoted attribute
	//   values because they can tickle parser ambiguities.
	//   Quoting all attributes is the best policy.
	ErrBadHTML

	// ErrBranchEnd: "{{if}} branches end in different contexts"
	// Example:
	//   {{if .C}}<a href="{{end}}{{.X}}
	// Discussion:
	//   Package html/template statically examines each path through an
	//   {{if}}, {{range}}, or {{with}} to escape any following pipelines.
	//   The example is ambiguous since {{.X}} might be an HTML text node,
	//   or a URL prefix in an HTML attribute. The context of {{.X}} is
	//   used to figure out how to escape it, but that context depends on
	//   the run-time value of {{.C}} which is not statically known.
	//
	//   The problem is usually something like missing quotes or angle
	//   brackets, or can be avoided by refactoring to put the two contexts
	//   into different branches of an if, range or with. If the problem
	//   is in a {{range}} over a collection that should never be empty,
	//   adding a dummy {{else}} can help.
	ErrBranchEnd

	// ErrEndContext: "... ends in a non-text context: ..."
	// Examples:
	//   <div
	//

	//    {{end}}
	//   {{define "helper"}} document.write(' <div title=" ') {{end}}
	//
	//   "helper" does not produce a valid document fragment, so should
	//   not be Executed directly.
	ErrEndContext

	// ErrNoSuchTemplate: "no such template ..."
	// Examples:
	//   {{define "main"}}
{{end}}
	//   {{define "attrs"}}href="{{.URL}}"{{end}}
	// Discussion:
	//   Package html/template looks through template calls to compute the
	//   context.
	//   Here the {{.URL}} in "attrs" must be treated as a URL when called
	//   from "main", but you will get this error if "attrs" is not defined
	//   when "main" is parsed.
	ErrNoSuchTemplate

	// ErrOutputContext: "cannot compute output context for template ..."
	// Examples:
	//   {{define "t"}}{{if .T}}{{template "t" .T}}{{end}}{{.H}}",{{end}}
	// Discussion:
	//   A recursive template does not end in the same context in which it
	//   starts, and a reliable output context cannot be computed.
	//   Look for typos in the named template.
	//   If the template should not be called in the named start context,
	//   look for calls to that template in unexpected contexts.
	//   Maybe refactor recursive templates to not be recursive.
	ErrOutputContext

	// ErrPartialCharset: "unfinished JS regexp charset in ..."
	// Example:
	//
	// Discussion:
	//   Package html/template does not support interpolation into regular
	//   expression literal character sets.
	ErrPartialCharset

	// ErrPartialEscape: "unfinished escape sequence in ..."
	// Example:
	//
	// Discussion:
	//   Package html/template does not support actions following a
	//   backslash.
	//   This is usually an error and there are better solutions; for
	//   example
	//
	//   should work, and if {{.X}} is a partial escape sequence such as
	//   "xA0", mark the whole sequence as safe content: JSStr(`\xA0`)
	ErrPartialEscape

	// ErrRangeLoopReentry: "on range loop re-entry: ..."
	// Example:
	//
	// Discussion:
	//   If an iteration through a range would cause it to end in a
	//   different context than an earlier pass, there is no single context.
	//   In the example, there is missing a quote, so it is not clear
	//   whether {{.}} is meant to be inside a JS string or in a JS value
	//   context.  The second iteration would produce something like
	//
	//
	ErrRangeLoopReentry

	// ErrSlashAmbig: '/' could start a division or regexp.
	// Example:
	//
	// Discussion:
	//   The example above could produce `var x = 1/-2/i.test(s)...`
	//   in which the first '/' is a mathematical division operator or it
	//   could produce `/-2/i.test(s)` in which the first '/' starts a
	//   regexp literal.
	//   Look for missing semicolons inside branches, and maybe add
	//   parentheses to make it clear which interpretation you intend.
	ErrSlashAmbig
)

func (e *Error) Error() string {
	if e == nil {
		return "html/template: Unknown Error"
	} else if e.Line != 0 {
		return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description)
	} else if e.Name != "" {
		return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description)
	}
	return "html/template: " + e.Description
}

// errorf creates an error given a format string f and args.
// The template Name still needs to be supplied.
func errorf(k ErrorCode, line int, f string, args ...interface{}) *Error {
	return &Error{k, "", line, fmt.Sprintf(f, args...)}
}
<commit_msg>Revert nil error check change since we handle signals properly now<commit_after>// 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 template

import (
	"fmt"
)

// Error describes a problem encountered during template Escaping.
type Error struct {
	// ErrorCode describes the kind of error.
	ErrorCode ErrorCode
	// Name is the name of the template in which the error was encountered.
	Name string
	// Line is the line number of the error in the template source or 0.
	Line int
	// Description is a human-readable description of the problem.
	Description string
}

// ErrorCode is a code for a kind of error.
type ErrorCode int

// We define codes for each error that manifests while escaping templates, but
// escaped templates may also fail at runtime.
//
// Output: "ZgotmplZ"
// Example:
//
//   where {{.X}} evaluates to `javascript:...`
// Discussion:
//   "ZgotmplZ" is a special value that indicates that unsafe content reached a
//   CSS or URL context at runtime. The output of the example will be
//
//   If the data comes from a trusted source, use content types to exempt it
//   from filtering: URL(`javascript:...`).
const (
	// OK indicates the lack of an error.
	OK ErrorCode = iota

	// ErrAmbigContext: "... appears in an ambiguous URL context"
	// Example:
	//
	// Discussion:
	//   {{.X}} is in an ambiguous URL context since, depending on {{.C}},
	//  it may be either a URL suffix or a query parameter.
	//   Moving {{.X}} into the condition removes the ambiguity:
	//
	ErrAmbigContext

	// ErrBadHTML: "expected space, attr name, or end of tag, but got ...",
	//   "... in unquoted attr", "... in attribute name"
	// Example:
	//
	//   <href=foo>
	//   <form na<e=...>
	//   <option selected<
	// Discussion:
	//   This is often due to a typo in an HTML element, but some runes
	//   are banned in tag names, attribute names, and unquoted attribute
	//   values because they can tickle parser ambiguities.
	//   Quoting all attributes is the best policy.
	ErrBadHTML

	// ErrBranchEnd: "{{if}} branches end in different contexts"
	// Example:
	//   {{if .C}}<a href="{{end}}{{.X}}
	// Discussion:
	//   Package html/template statically examines each path through an
	//   {{if}}, {{range}}, or {{with}} to escape any following pipelines.
	//   The example is ambiguous since {{.X}} might be an HTML text node,
	//   or a URL prefix in an HTML attribute. The context of {{.X}} is
	//   used to figure out how to escape it, but that context depends on
	//   the run-time value of {{.C}} which is not statically known.
	//
	//   The problem is usually something like missing quotes or angle
	//   brackets, or can be avoided by refactoring to put the two contexts
	//   into different branches of an if, range or with. If the problem
	//   is in a {{range}} over a collection that should never be empty,
	//   adding a dummy {{else}} can help.
	ErrBranchEnd

	// ErrEndContext: "... ends in a non-text context: ..."
	// Examples:
	//   <div
	//

	//    {{end}}
	//   {{define "helper"}} document.write(' <div title=" ') {{end}}
	//
	//   "helper" does not produce a valid document fragment, so should
	//   not be Executed directly.
	ErrEndContext

	// ErrNoSuchTemplate: "no such template ..."
	// Examples:
	//   {{define "main"}}
{{end}}
	//   {{define "attrs"}}href="{{.URL}}"{{end}}
	// Discussion:
	//   Package html/template looks through template calls to compute the
	//   context.
	//   Here the {{.URL}} in "attrs" must be treated as a URL when called
	//   from "main", but you will get this error if "attrs" is not defined
	//   when "main" is parsed.
	ErrNoSuchTemplate

	// ErrOutputContext: "cannot compute output context for template ..."
	// Examples:
	//   {{define "t"}}{{if .T}}{{template "t" .T}}{{end}}{{.H}}",{{end}}
	// Discussion:
	//   A recursive template does not end in the same context in which it
	//   starts, and a reliable output context cannot be computed.
	//   Look for typos in the named template.
	//   If the template should not be called in the named start context,
	//   look for calls to that template in unexpected contexts.
	//   Maybe refactor recursive templates to not be recursive.
	ErrOutputContext

	// ErrPartialCharset: "unfinished JS regexp charset in ..."
	// Example:
	//
	// Discussion:
	//   Package html/template does not support interpolation into regular
	//   expression literal character sets.
	ErrPartialCharset

	// ErrPartialEscape: "unfinished escape sequence in ..."
	// Example:
	//
	// Discussion:
	//   Package html/template does not support actions following a
	//   backslash.
	//   This is usually an error and there are better solutions; for
	//   example
	//
	//   should work, and if {{.X}} is a partial escape sequence such as
	//   "xA0", mark the whole sequence as safe content: JSStr(`\xA0`)
	ErrPartialEscape

	// ErrRangeLoopReentry: "on range loop re-entry: ..."
	// Example:
	//
	// Discussion:
	//   If an iteration through a range would cause it to end in a
	//   different context than an earlier pass, there is no single context.
	//   In the example, there is missing a quote, so it is not clear
	//   whether {{.}} is meant to be inside a JS string or in a JS value
	//   context.  The second iteration would produce something like
	//
	//
	ErrRangeLoopReentry

	// ErrSlashAmbig: '/' could start a division or regexp.
	// Example:
	//
	// Discussion:
	//   The example above could produce `var x = 1/-2/i.test(s)...`
	//   in which the first '/' is a mathematical division operator or it
	//   could produce `/-2/i.test(s)` in which the first '/' starts a
	//   regexp literal.
	//   Look for missing semicolons inside branches, and maybe add
	//   parentheses to make it clear which interpretation you intend.
	ErrSlashAmbig
)

func (e *Error) Error() string {
	if e.Line != 0 {
		return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description)
	} else if e.Name != "" {
		return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description)
	}
	return "html/template: " + e.Description
}

// errorf creates an error given a format string f and args.
// The template Name still needs to be supplied.
func errorf(k ErrorCode, line int, f string, args ...interface{}) *Error {
	return &Error{k, "", line, fmt.Sprintf(f, args...)}
}
<|endoftext|>


<commit_before>// Copyright 2016-2019 terraform-provider-sakuracloud authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sakuracloud

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/hashicorp/terraform-plugin-sdk/httpclient"
	"github.com/sacloud/libsacloud/v2/sacloud"
	"github.com/sacloud/libsacloud/v2/sacloud/fake"
	"github.com/sacloud/libsacloud/v2/sacloud/trace"
	"github.com/sacloud/libsacloud/v2/utils/builder"
	"github.com/sacloud/libsacloud/v2/utils/setup"
)

const (
	traceHTTP = "http"
	traceAPI  = "api"
)

const uaEnvVar = "SAKURACLOUD_APPEND_USER_AGENT"

var (
	fakeModeOnce                    sync.Once
	v2ClientOnce                    sync.Once
	deletionWaiterTimeout           = 30 * time.Minute
	deletionWaiterPollingInterval   = 5 * time.Second
	databaseWaitAfterCreateDuration = 1 * time.Minute
)

// Config type of SakuraCloud Config
type Config struct {
	AccessToken         string
	AccessTokenSecret   string
	Zone                string
	Zones               []string
	TraceMode           string
	FakeMode            string
	FakeStorePath       string
	AcceptLanguage      string
	APIRootURL          string
	RetryMax            int
	RetryInterval       int
	APIRequestTimeout   int
	APIRequestRateLimit int

	terraformVersion string
	initOnce         sync.Once
}

// APIClient for SakuraCloud API
type APIClient struct {
	sacloud.APICaller
	defaultZone                     string
	zones                           []string
	deletionWaiterTimeout           time.Duration
	deletionWaiterPollingInterval   time.Duration
	databaseWaitAfterCreateDuration time.Duration
}

// NewClient returns new API Client for SakuraCloud
func (c *Config) NewClient() *APIClient {

	tfUserAgent := httpclient.TerraformUserAgent(c.terraformVersion)
	providerUserAgent := fmt.Sprintf("%s/v%s", "terraform-provider-sakuracloud", Version)
	ua := fmt.Sprintf("%s %s", tfUserAgent, providerUserAgent)
	if add := os.Getenv(uaEnvVar); add != "" {
		ua += " " + add
		log.Printf("[DEBUG] Using modified User-Agent: %s", ua)
	}

	httpClient := &http.Client{
		Timeout:   time.Duration(c.APIRequestTimeout) * time.Second,
		Transport: &sacloud.RateLimitRoundTripper{RateLimitPerSec: c.APIRequestRateLimit},
	}
	caller := &sacloud.Client{
		AccessToken:       c.AccessToken,
		AccessTokenSecret: c.AccessTokenSecret,
		UserAgent:         ua,
		AcceptLanguage:    c.AcceptLanguage,
		RetryMax:          c.RetryMax,
		RetryInterval:     time.Duration(c.RetryInterval) * time.Second,
		HTTPClient:        httpClient,
	}
	sacloud.DefaultStatePollingTimeout = 72 * time.Hour

	if c.TraceMode != "" {
		enableAPITrace := true
		enableHTTPTrace := true

		mode := strings.ToLower(c.TraceMode)
		switch mode {
		case traceAPI:
			enableHTTPTrace = false
		case traceHTTP:
			enableAPITrace = false
		}

		if enableAPITrace {
			v2ClientOnce.Do(func() {
				trace.AddClientFactoryHooks()
			})
		}
		if enableHTTPTrace {
			caller.HTTPClient.Transport = &sacloud.TracingRoundTripper{
				Transport: caller.HTTPClient.Transport,
			}
		}
	}

	if c.FakeMode != "" {
		if c.FakeStorePath != "" {
			fake.DataStore = fake.NewJSONFileStore(c.FakeStorePath)
		}
		fakeModeOnce.Do(func() {
			fake.SwitchFactoryFuncToFake()
		})

		// TODO パラメータ化
		deletionWaiterTimeout = 10 * time.Second
		defaultInterval := 10 * time.Millisecond
		deletionWaiterPollingInterval = defaultInterval
		databaseWaitAfterCreateDuration = defaultInterval

		// update default polling intervals: libsacloud/sacloud
		sacloud.DefaultStatePollingInterval = defaultInterval
		sacloud.APIDefaultRetryInterval = defaultInterval
		// update default polling intervals: libsacloud/utils/setup
		setup.DefaultDeleteWaitInterval = defaultInterval
		setup.DefaultProvisioningWaitInterval = defaultInterval
		setup.DefaultPollingInterval = defaultInterval
		// update default polling intervals: libsacloud/utils/builder
		builder.DefaultNICUpdateWaitDuration = defaultInterval
	}

	zones := c.Zones
	if len(zones) == 0 {
		zones = defaultZones
	}
	if c.APIRootURL != "" {
		if strings.HasSuffix(c.APIRootURL, "/") {
			c.APIRootURL = strings.TrimRight(c.APIRootURL, "/")
		}
		sacloud.SakuraCloudAPIRoot = c.APIRootURL
	}

	return &APIClient{
		APICaller:                       caller,
		defaultZone:                     c.Zone,
		zones:                           zones,
		deletionWaiterTimeout:           deletionWaiterTimeout,
		deletionWaiterPollingInterval:   deletionWaiterPollingInterval,
		databaseWaitAfterCreateDuration: databaseWaitAfterCreateDuration,
	}
}
<commit_msg>lint: structcheck<commit_after>// Copyright 2016-2019 terraform-provider-sakuracloud authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sakuracloud

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/hashicorp/terraform-plugin-sdk/httpclient"
	"github.com/sacloud/libsacloud/v2/sacloud"
	"github.com/sacloud/libsacloud/v2/sacloud/fake"
	"github.com/sacloud/libsacloud/v2/sacloud/trace"
	"github.com/sacloud/libsacloud/v2/utils/builder"
	"github.com/sacloud/libsacloud/v2/utils/setup"
)

const (
	traceHTTP = "http"
	traceAPI  = "api"
)

const uaEnvVar = "SAKURACLOUD_APPEND_USER_AGENT"

var (
	fakeModeOnce                    sync.Once
	v2ClientOnce                    sync.Once
	deletionWaiterTimeout           = 30 * time.Minute
	deletionWaiterPollingInterval   = 5 * time.Second
	databaseWaitAfterCreateDuration = 1 * time.Minute
)

// Config type of SakuraCloud Config
type Config struct {
	AccessToken         string
	AccessTokenSecret   string
	Zone                string
	Zones               []string
	TraceMode           string
	FakeMode            string
	FakeStorePath       string
	AcceptLanguage      string
	APIRootURL          string
	RetryMax            int
	RetryInterval       int
	APIRequestTimeout   int
	APIRequestRateLimit int

	terraformVersion string
}

// APIClient for SakuraCloud API
type APIClient struct {
	sacloud.APICaller
	defaultZone                     string
	zones                           []string
	deletionWaiterTimeout           time.Duration
	deletionWaiterPollingInterval   time.Duration
	databaseWaitAfterCreateDuration time.Duration
}

// NewClient returns new API Client for SakuraCloud
func (c *Config) NewClient() *APIClient {

	tfUserAgent := httpclient.TerraformUserAgent(c.terraformVersion)
	providerUserAgent := fmt.Sprintf("%s/v%s", "terraform-provider-sakuracloud", Version)
	ua := fmt.Sprintf("%s %s", tfUserAgent, providerUserAgent)
	if add := os.Getenv(uaEnvVar); add != "" {
		ua += " " + add
		log.Printf("[DEBUG] Using modified User-Agent: %s", ua)
	}

	httpClient := &http.Client{
		Timeout:   time.Duration(c.APIRequestTimeout) * time.Second,
		Transport: &sacloud.RateLimitRoundTripper{RateLimitPerSec: c.APIRequestRateLimit},
	}
	caller := &sacloud.Client{
		AccessToken:       c.AccessToken,
		AccessTokenSecret: c.AccessTokenSecret,
		UserAgent:         ua,
		AcceptLanguage:    c.AcceptLanguage,
		RetryMax:          c.RetryMax,
		RetryInterval:     time.Duration(c.RetryInterval) * time.Second,
		HTTPClient:        httpClient,
	}
	sacloud.DefaultStatePollingTimeout = 72 * time.Hour

	if c.TraceMode != "" {
		enableAPITrace := true
		enableHTTPTrace := true

		mode := strings.ToLower(c.TraceMode)
		switch mode {
		case traceAPI:
			enableHTTPTrace = false
		case traceHTTP:
			enableAPITrace = false
		}

		if enableAPITrace {
			v2ClientOnce.Do(func() {
				trace.AddClientFactoryHooks()
			})
		}
		if enableHTTPTrace {
			caller.HTTPClient.Transport = &sacloud.TracingRoundTripper{
				Transport: caller.HTTPClient.Transport,
			}
		}
	}

	if c.FakeMode != "" {
		if c.FakeStorePath != "" {
			fake.DataStore = fake.NewJSONFileStore(c.FakeStorePath)
		}
		fakeModeOnce.Do(func() {
			fake.SwitchFactoryFuncToFake()
		})

		// TODO パラメータ化
		deletionWaiterTimeout = 10 * time.Second
		defaultInterval := 10 * time.Millisecond
		deletionWaiterPollingInterval = defaultInterval
		databaseWaitAfterCreateDuration = defaultInterval

		// update default polling intervals: libsacloud/sacloud
		sacloud.DefaultStatePollingInterval = defaultInterval
		sacloud.APIDefaultRetryInterval = defaultInterval
		// update default polling intervals: libsacloud/utils/setup
		setup.DefaultDeleteWaitInterval = defaultInterval
		setup.DefaultProvisioningWaitInterval = defaultInterval
		setup.DefaultPollingInterval = defaultInterval
		// update default polling intervals: libsacloud/utils/builder
		builder.DefaultNICUpdateWaitDuration = defaultInterval
	}

	zones := c.Zones
	if len(zones) == 0 {
		zones = defaultZones
	}
	if c.APIRootURL != "" {
		if strings.HasSuffix(c.APIRootURL, "/") {
			c.APIRootURL = strings.TrimRight(c.APIRootURL, "/")
		}
		sacloud.SakuraCloudAPIRoot = c.APIRootURL
	}

	return &APIClient{
		APICaller:                       caller,
		defaultZone:                     c.Zone,
		zones:                           zones,
		deletionWaiterTimeout:           deletionWaiterTimeout,
		deletionWaiterPollingInterval:   deletionWaiterPollingInterval,
		databaseWaitAfterCreateDuration: databaseWaitAfterCreateDuration,
	}
}
<|endoftext|>


<commit_before>/*
Copyright The Helm Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package chartutil

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/golang/protobuf/ptypes/any"

	"k8s.io/helm/pkg/ignore"
	"k8s.io/helm/pkg/proto/hapi/chart"
	"k8s.io/helm/pkg/sympath"
)

// Load takes a string name, tries to resolve it to a file or directory, and then loads it.
//
// This is the preferred way to load a chart. It will discover the chart encoding
// and hand off to the appropriate chart reader.
//
// If a .helmignore file is present, the directory loader will skip loading any files
// matching it. But .helmignore is not evaluated when reading out of an archive.
func Load(name string) (*chart.Chart, error) {
	name = filepath.FromSlash(name)
	fi, err := os.Stat(name)
	if err != nil {
		return nil, err
	}
	if fi.IsDir() {
		if validChart, err := IsChartDir(name); !validChart {
			return nil, err
		}
		return LoadDir(name)
	}
	return LoadFile(name)
}

// BufferedFile represents an archive file buffered for later processing.
type BufferedFile struct {
	Name string
	Data []byte
}

var drivePathPattern = regexp.MustCompile(`^[a-zA-Z]:/`)

// loadArchiveFiles loads files out of an archive
func loadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
	unzipped, err := gzip.NewReader(in)
	if err != nil {
		return nil, err
	}
	defer unzipped.Close()

	files := []*BufferedFile{}
	tr := tar.NewReader(unzipped)
	for {
		b := bytes.NewBuffer(nil)
		hd, err := tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}

		if hd.FileInfo().IsDir() {
			// Use this instead of hd.Typeflag because we don't have to do any
			// inference chasing.
			continue
		}

		// Archive could contain \ if generated on Windows
		delimiter := "/"
		if strings.ContainsRune(hd.Name, '\\') {
			delimiter = "\\"
		}

		parts := strings.Split(hd.Name, delimiter)
		n := strings.Join(parts[1:], delimiter)

		// Normalize the path to the / delimiter
		n = strings.Replace(n, delimiter, "/", -1)

		if path.IsAbs(n) {
			return nil, errors.New("chart illegally contains absolute paths")
		}

		n = path.Clean(n)
		if n == "." {
			// In this case, the original path was relative when it should have been absolute.
			return nil, errors.New("chart illegally contains empty path")
		}
		if strings.HasPrefix(n, "..") {
			return nil, errors.New("chart illegally references parent directory")
		}

		// In some particularly arcane acts of path creativity, it is possible to intermix
		// UNIX and Windows style paths in such a way that you produce a result of the form
		// c:/foo even after all the built-in absolute path checks. So we explicitly check
		// for this condition.
		if drivePathPattern.MatchString(n) {
			return nil, errors.New("chart contains illegally named files")
		}

		if parts[0] == "Chart.yaml" {
			return nil, errors.New("chart yaml not in base directory")
		}

		if _, err := io.Copy(b, tr); err != nil {
			return files, err
		}

		files = append(files, &BufferedFile{Name: n, Data: b.Bytes()})
		b.Reset()
	}

	if len(files) == 0 {
		return nil, errors.New("no files in chart archive")
	}
	return files, nil
}

// LoadArchive loads from a reader containing a compressed tar archive.
func LoadArchive(in io.Reader) (*chart.Chart, error) {
	files, err := loadArchiveFiles(in)
	if err != nil {
		return nil, err
	}
	return LoadFiles(files)
}

// LoadFiles loads from in-memory files.
func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
	c := &chart.Chart{}
	subcharts := map[string][]*BufferedFile{}

	for _, f := range files {
		if f.Name == "Chart.yaml" {
			m, err := UnmarshalChartfile(f.Data)
			if err != nil {
				return c, err
			}
			c.Metadata = m
		} else if f.Name == "values.toml" {
			return c, errors.New("values.toml is illegal as of 2.0.0-alpha.2")
		} else if f.Name == "values.yaml" {
			c.Values = &chart.Config{Raw: string(f.Data)}
		} else if strings.HasPrefix(f.Name, "templates/") {
			c.Templates = append(c.Templates, &chart.Template{Name: f.Name, Data: f.Data})
		} else if strings.HasPrefix(f.Name, "charts/") {
			if filepath.Ext(f.Name) == ".prov" {
				c.Files = append(c.Files, &any.Any{TypeUrl: f.Name, Value: f.Data})
				continue
			}
			cname := strings.TrimPrefix(f.Name, "charts/")
			if strings.IndexAny(cname, "._") == 0 {
				// Ignore charts/ that start with . or _.
				continue
			}
			parts := strings.SplitN(cname, "/", 2)
			scname := parts[0]
			subcharts[scname] = append(subcharts[scname], &BufferedFile{Name: cname, Data: f.Data})
		} else {
			c.Files = append(c.Files, &any.Any{TypeUrl: f.Name, Value: f.Data})
		}
	}

	// Ensure that we got a Chart.yaml file
	if c.Metadata == nil {
		return c, errors.New("chart metadata (Chart.yaml) missing")
	}
	if c.Metadata.Name == "" {
		return c, errors.New("invalid chart (Chart.yaml): name must not be empty")
	}

	for n, files := range subcharts {
		var sc *chart.Chart
		var err error
		if strings.IndexAny(n, "_.") == 0 {
			continue
		} else if filepath.Ext(n) == ".tgz" {
			file := files[0]
			if file.Name != n {
				return c, fmt.Errorf("error unpacking tar in %s: expected %s, got %s", c.Metadata.Name, n, file.Name)
			}
			// Untar the chart and add to c.Dependencies
			b := bytes.NewBuffer(file.Data)
			sc, err = LoadArchive(b)
		} else {
			// We have to trim the prefix off of every file, and ignore any file
			// that is in charts/, but isn't actually a chart.
			buff := make([]*BufferedFile, 0, len(files))
			for _, f := range files {
				parts := strings.SplitN(f.Name, "/", 2)
				if len(parts) < 2 {
					continue
				}
				f.Name = parts[1]
				buff = append(buff, f)
			}
			sc, err = LoadFiles(buff)
		}

		if err != nil {
			return c, fmt.Errorf("error unpacking %s in %s: %s", n, c.Metadata.Name, err)
		}

		c.Dependencies = append(c.Dependencies, sc)
	}

	return c, nil
}

// LoadFile loads from an archive file.
func LoadFile(name string) (*chart.Chart, error) {
	if fi, err := os.Stat(name); err != nil {
		return nil, err
	} else if fi.IsDir() {
		return nil, errors.New("cannot load a directory")
	}

	raw, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	defer raw.Close()

	return LoadArchive(raw)
}

// LoadDir loads from a directory.
//
// This loads charts only from directories.
func LoadDir(dir string) (*chart.Chart, error) {
	topdir, err := filepath.Abs(dir)
	if err != nil {
		return nil, err
	}

	// Just used for errors.
	c := &chart.Chart{}

	rules := ignore.Empty()
	ifile := filepath.Join(topdir, ignore.HelmIgnore)
	if _, err := os.Stat(ifile); err == nil {
		r, err := ignore.ParseFile(ifile)
		if err != nil {
			return c, err
		}
		rules = r
	}
	rules.AddDefaults()

	files := []*BufferedFile{}
	topdir += string(filepath.Separator)

	walk := func(name string, fi os.FileInfo, err error) error {
		n := strings.TrimPrefix(name, topdir)
		if n == "" {
			// No need to process top level. Avoid bug with helmignore .* matching
			// empty names. See issue 1779.
			return nil
		}

		// Normalize to / since it will also work on Windows
		n = filepath.ToSlash(n)

		if err != nil {
			return err
		}
		if fi.IsDir() {
			// Directory-based ignore rules should involve skipping the entire
			// contents of that directory.
			if rules.Ignore(n, fi) {
				return filepath.SkipDir
			}
			return nil
		}

		// If a .helmignore file matches, skip this file.
		if rules.Ignore(n, fi) {
			return nil
		}

		data, err := ioutil.ReadFile(name)
		if err != nil {
			return fmt.Errorf("error reading %s: %s", n, err)
		}

		files = append(files, &BufferedFile{Name: n, Data: data})
		return nil
	}
	if err = sympath.Walk(topdir, walk); err != nil {
		return c, err
	}

	return LoadFiles(files)
}
<commit_msg>fix: ignore pax header "file"s in chart validation<commit_after>/*
Copyright The Helm Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package chartutil

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/golang/protobuf/ptypes/any"

	"k8s.io/helm/pkg/ignore"
	"k8s.io/helm/pkg/proto/hapi/chart"
	"k8s.io/helm/pkg/sympath"
)

// Load takes a string name, tries to resolve it to a file or directory, and then loads it.
//
// This is the preferred way to load a chart. It will discover the chart encoding
// and hand off to the appropriate chart reader.
//
// If a .helmignore file is present, the directory loader will skip loading any files
// matching it. But .helmignore is not evaluated when reading out of an archive.
func Load(name string) (*chart.Chart, error) {
	name = filepath.FromSlash(name)
	fi, err := os.Stat(name)
	if err != nil {
		return nil, err
	}
	if fi.IsDir() {
		if validChart, err := IsChartDir(name); !validChart {
			return nil, err
		}
		return LoadDir(name)
	}
	return LoadFile(name)
}

// BufferedFile represents an archive file buffered for later processing.
type BufferedFile struct {
	Name string
	Data []byte
}

var drivePathPattern = regexp.MustCompile(`^[a-zA-Z]:/`)

// loadArchiveFiles loads files out of an archive
func loadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
	unzipped, err := gzip.NewReader(in)
	if err != nil {
		return nil, err
	}
	defer unzipped.Close()

	files := []*BufferedFile{}
	tr := tar.NewReader(unzipped)
	for {
		b := bytes.NewBuffer(nil)
		hd, err := tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return nil, err
		}

		if hd.FileInfo().IsDir() {
			// Use this instead of hd.Typeflag because we don't have to do any
			// inference chasing.
			continue
		}

		switch hd.Typeflag {
		// We don't want to process these extension header files.
		case tar.TypeXGlobalHeader, tar.TypeXHeader:
			continue
		}

		// Archive could contain \ if generated on Windows
		delimiter := "/"
		if strings.ContainsRune(hd.Name, '\\') {
			delimiter = "\\"
		}

		parts := strings.Split(hd.Name, delimiter)
		n := strings.Join(parts[1:], delimiter)

		// Normalize the path to the / delimiter
		n = strings.Replace(n, delimiter, "/", -1)

		if path.IsAbs(n) {
			return nil, errors.New("chart illegally contains absolute paths")
		}

		n = path.Clean(n)
		if n == "." {
			// In this case, the original path was relative when it should have been absolute.
			return nil, errors.New("chart illegally contains empty path")
		}
		if strings.HasPrefix(n, "..") {
			return nil, errors.New("chart illegally references parent directory")
		}

		// In some particularly arcane acts of path creativity, it is possible to intermix
		// UNIX and Windows style paths in such a way that you produce a result of the form
		// c:/foo even after all the built-in absolute path checks. So we explicitly check
		// for this condition.
		if drivePathPattern.MatchString(n) {
			return nil, errors.New("chart contains illegally named files")
		}

		if parts[0] == "Chart.yaml" {
			return nil, errors.New("chart yaml not in base directory")
		}

		if _, err := io.Copy(b, tr); err != nil {
			return files, err
		}

		files = append(files, &BufferedFile{Name: n, Data: b.Bytes()})
		b.Reset()
	}

	if len(files) == 0 {
		return nil, errors.New("no files in chart archive")
	}
	return files, nil
}

// LoadArchive loads from a reader containing a compressed tar archive.
func LoadArchive(in io.Reader) (*chart.Chart, error) {
	files, err := loadArchiveFiles(in)
	if err != nil {
		return nil, err
	}
	return LoadFiles(files)
}

// LoadFiles loads from in-memory files.
func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
	c := &chart.Chart{}
	subcharts := map[string][]*BufferedFile{}

	for _, f := range files {
		if f.Name == "Chart.yaml" {
			m, err := UnmarshalChartfile(f.Data)
			if err != nil {
				return c, err
			}
			c.Metadata = m
		} else if f.Name == "values.toml" {
			return c, errors.New("values.toml is illegal as of 2.0.0-alpha.2")
		} else if f.Name == "values.yaml" {
			c.Values = &chart.Config{Raw: string(f.Data)}
		} else if strings.HasPrefix(f.Name, "templates/") {
			c.Templates = append(c.Templates, &chart.Template{Name: f.Name, Data: f.Data})
		} else if strings.HasPrefix(f.Name, "charts/") {
			if filepath.Ext(f.Name) == ".prov" {
				c.Files = append(c.Files, &any.Any{TypeUrl: f.Name, Value: f.Data})
				continue
			}
			cname := strings.TrimPrefix(f.Name, "charts/")
			if strings.IndexAny(cname, "._") == 0 {
				// Ignore charts/ that start with . or _.
				continue
			}
			parts := strings.SplitN(cname, "/", 2)
			scname := parts[0]
			subcharts[scname] = append(subcharts[scname], &BufferedFile{Name: cname, Data: f.Data})
		} else {
			c.Files = append(c.Files, &any.Any{TypeUrl: f.Name, Value: f.Data})
		}
	}

	// Ensure that we got a Chart.yaml file
	if c.Metadata == nil {
		return c, errors.New("chart metadata (Chart.yaml) missing")
	}
	if c.Metadata.Name == "" {
		return c, errors.New("invalid chart (Chart.yaml): name must not be empty")
	}

	for n, files := range subcharts {
		var sc *chart.Chart
		var err error
		if strings.IndexAny(n, "_.") == 0 {
			continue
		} else if filepath.Ext(n) == ".tgz" {
			file := files[0]
			if file.Name != n {
				return c, fmt.Errorf("error unpacking tar in %s: expected %s, got %s", c.Metadata.Name, n, file.Name)
			}
			// Untar the chart and add to c.Dependencies
			b := bytes.NewBuffer(file.Data)
			sc, err = LoadArchive(b)
		} else {
			// We have to trim the prefix off of every file, and ignore any file
			// that is in charts/, but isn't actually a chart.
			buff := make([]*BufferedFile, 0, len(files))
			for _, f := range files {
				parts := strings.SplitN(f.Name, "/", 2)
				if len(parts) < 2 {
					continue
				}
				f.Name = parts[1]
				buff = append(buff, f)
			}
			sc, err = LoadFiles(buff)
		}

		if err != nil {
			return c, fmt.Errorf("error unpacking %s in %s: %s", n, c.Metadata.Name, err)
		}

		c.Dependencies = append(c.Dependencies, sc)
	}

	return c, nil
}

// LoadFile loads from an archive file.
func LoadFile(name string) (*chart.Chart, error) {
	if fi, err := os.Stat(name); err != nil {
		return nil, err
	} else if fi.IsDir() {
		return nil, errors.New("cannot load a directory")
	}

	raw, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	defer raw.Close()

	return LoadArchive(raw)
}

// LoadDir loads from a directory.
//
// This loads charts only from directories.
func LoadDir(dir string) (*chart.Chart, error) {
	topdir, err := filepath.Abs(dir)
	if err != nil {
		return nil, err
	}

	// Just used for errors.
	c := &chart.Chart{}

	rules := ignore.Empty()
	ifile := filepath.Join(topdir, ignore.HelmIgnore)
	if _, err := os.Stat(ifile); err == nil {
		r, err := ignore.ParseFile(ifile)
		if err != nil {
			return c, err
		}
		rules = r
	}
	rules.AddDefaults()

	files := []*BufferedFile{}
	topdir += string(filepath.Separator)

	walk := func(name string, fi os.FileInfo, err error) error {
		n := strings.TrimPrefix(name, topdir)
		if n == "" {
			// No need to process top level. Avoid bug with helmignore .* matching
			// empty names. See issue 1779.
			return nil
		}

		// Normalize to / since it will also work on Windows
		n = filepath.ToSlash(n)

		if err != nil {
			return err
		}
		if fi.IsDir() {
			// Directory-based ignore rules should involve skipping the entire
			// contents of that directory.
			if rules.Ignore(n, fi) {
				return filepath.SkipDir
			}
			return nil
		}

		// If a .helmignore file matches, skip this file.
		if rules.Ignore(n, fi) {
			return nil
		}

		data, err := ioutil.ReadFile(name)
		if err != nil {
			return fmt.Errorf("error reading %s: %s", n, err)
		}

		files = append(files, &BufferedFile{Name: n, Data: data})
		return nil
	}
	if err = sympath.Walk(topdir, walk); err != nil {
		return c, err
	}

	return LoadFiles(files)
}
<|endoftext|>


<commit_before>// 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.

// The httptest package provides utilities for HTTP testing.
package httptest

import (
	"bytes"
	"http"
	"os"
)

// ResponseRecorder is an implementation of http.ResponseWriter that
// records its mutations for later inspection in tests.
type ResponseRecorder struct {
	Code      int           // the HTTP response code from WriteHeader
	HeaderMap http.Header   // the HTTP response headers
	Body      *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
	Flushed   bool
}

// NewRecorder returns an initialized ResponseRecorder.
func NewRecorder() *ResponseRecorder {
	return &ResponseRecorder{
		HeaderMap: make(http.Header),
		Body:      new(bytes.Buffer),
	}
}

// DefaultRemoteAddr is the default remote address to return in RemoteAddr if
// an explicit DefaultRemoteAddr isn't set on ResponseRecorder.
const DefaultRemoteAddr = "1.2.3.4"

// Header returns the response headers.
func (rw *ResponseRecorder) Header() http.Header {
	return rw.HeaderMap
}

// Write always succeeds and writes to rw.Body, if not nil.
func (rw *ResponseRecorder) Write(buf []byte) (int, os.Error) {
	if rw.Body != nil {
		rw.Body.Write(buf)
	}
	return len(buf), nil
}

// WriteHeader sets rw.Code.
func (rw *ResponseRecorder) WriteHeader(code int) {
	rw.Code = code
}

// Flush sets rw.Flushed to true.
func (rw *ResponseRecorder) Flush() {
	rw.Flushed = true
}
<commit_msg>httptest: default the Recorder status code to 200 on a Write<commit_after>// 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.

// The httptest package provides utilities for HTTP testing.
package httptest

import (
	"bytes"
	"http"
	"os"
)

// ResponseRecorder is an implementation of http.ResponseWriter that
// records its mutations for later inspection in tests.
type ResponseRecorder struct {
	Code      int           // the HTTP response code from WriteHeader
	HeaderMap http.Header   // the HTTP response headers
	Body      *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
	Flushed   bool
}

// NewRecorder returns an initialized ResponseRecorder.
func NewRecorder() *ResponseRecorder {
	return &ResponseRecorder{
		HeaderMap: make(http.Header),
		Body:      new(bytes.Buffer),
	}
}

// DefaultRemoteAddr is the default remote address to return in RemoteAddr if
// an explicit DefaultRemoteAddr isn't set on ResponseRecorder.
const DefaultRemoteAddr = "1.2.3.4"

// Header returns the response headers.
func (rw *ResponseRecorder) Header() http.Header {
	return rw.HeaderMap
}

// Write always succeeds and writes to rw.Body, if not nil.
func (rw *ResponseRecorder) Write(buf []byte) (int, os.Error) {
	if rw.Body != nil {
		rw.Body.Write(buf)
	}
	if rw.Code == 0 {
		rw.Code = http.StatusOK
	}
	return len(buf), nil
}

// WriteHeader sets rw.Code.
func (rw *ResponseRecorder) WriteHeader(code int) {
	rw.Code = code
}

// Flush sets rw.Flushed to true.
func (rw *ResponseRecorder) Flush() {
	rw.Flushed = true
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package master

import (
	"crypto/x509"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"time"

	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/extensions"
	clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
	certutil "k8s.io/kubernetes/pkg/util/cert"
	"k8s.io/kubernetes/pkg/util/wait"
)

type kubeDiscovery struct {
	Deployment *extensions.Deployment
	Secret     *api.Secret
}

const (
	kubeDiscoveryName       = "kube-discovery"
	kubeDiscoverySecretName = "clusterinfo"
)

func encodeKubeDiscoverySecretData(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate) map[string][]byte {
	var (
		data         = map[string][]byte{}
		endpointList = []string{}
		tokenMap     = map[string]string{}
	)

	for _, addr := range s.InitFlags.API.AdvertiseAddrs {
		endpointList = append(endpointList, fmt.Sprintf("https://%s:443", addr.String()))
	}

	tokenMap[s.Secrets.TokenID] = hex.EncodeToString(s.Secrets.Token)

	data["endpoint-list.json"], _ = json.Marshal(endpointList)
	data["token-map.json"], _ = json.Marshal(tokenMap)
	data["ca.pem"] = certutil.EncodeCertPEM(caCert)

	return data
}

func newKubeDiscoveryPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec {
	return api.PodSpec{
		// We have to use host network namespace, as `HostPort`/`HostIP` are Docker's
		// buisness and CNI support isn't quite there yet (except for kubenet)
		// (see https://github.com/kubernetes/kubernetes/issues/31307)
		// TODO update this when #31307 is resolved
		SecurityContext: &api.PodSecurityContext{HostNetwork: true},
		Containers: []api.Container{{
			Name:    kubeDiscoveryName,
			Image:   s.EnvParams["discovery_image"],
			Command: []string{"/usr/local/bin/kube-discovery"},
			VolumeMounts: []api.VolumeMount{{
				Name:      kubeDiscoverySecretName,
				MountPath: "/tmp/secret", // TODO use a shared constant
				ReadOnly:  true,
			}},
			Ports: []api.ContainerPort{
				// TODO when CNI issue (#31307) is resolved, we should consider adding
				// `HostIP: s.API.AdvertiseAddrs[0]`, if there is only one address`
				{Name: "http", ContainerPort: 9898, HostPort: 9898},
			},
		}},
		Volumes: []api.Volume{{
			Name: kubeDiscoverySecretName,
			VolumeSource: api.VolumeSource{
				Secret: &api.SecretVolumeSource{SecretName: kubeDiscoverySecretName},
			}},
		},
	}
}

func newKubeDiscovery(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate) kubeDiscovery {
	kd := kubeDiscovery{
		Deployment: NewDeployment(kubeDiscoveryName, 1, newKubeDiscoveryPodSpec(s)),
		Secret: &api.Secret{
			ObjectMeta: api.ObjectMeta{Name: kubeDiscoverySecretName},
			Type:       api.SecretTypeOpaque,
			Data:       encodeKubeDiscoverySecretData(s, caCert),
		},
	}

	SetMasterTaintTolerations(&kd.Deployment.Spec.Template.ObjectMeta)
	SetMasterNodeAffinity(&kd.Deployment.Spec.Template.ObjectMeta)

	return kd
}

func CreateDiscoveryDeploymentAndSecret(s *kubeadmapi.KubeadmConfig, client *clientset.Clientset, caCert *x509.Certificate) error {
	kd := newKubeDiscovery(s, caCert)

	if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kd.Deployment); err != nil {
		return fmt.Errorf("<master/discovery> failed to create %q deployment [%s]", kubeDiscoveryName, err)
	}
	if _, err := client.Secrets(api.NamespaceSystem).Create(kd.Secret); err != nil {
		return fmt.Errorf("<master/discovery> failed to create %q secret [%s]", kubeDiscoverySecretName, err)
	}

	fmt.Println("<master/discovery> created essential addon: kube-discovery, waiting for it to become ready")

	start := time.Now()
	wait.PollInfinite(apiCallRetryInterval, func() (bool, error) {
		d, err := client.Extensions().Deployments(api.NamespaceSystem).Get(kubeDiscoveryName)
		if err != nil {
			return false, nil
		}
		if d.Status.AvailableReplicas < 1 {
			return false, nil
		}
		return true, nil
	})
	fmt.Printf("<master/discovery> kube-discovery is ready after %f seconds\n", time.Since(start).Seconds())

	return nil
}
<commit_msg>Fix boostrap token encoding bug during master init<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package master

import (
	"crypto/x509"
	"encoding/json"
	"fmt"
	"time"

	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/api"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/apis/extensions"
	clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
	certutil "k8s.io/kubernetes/pkg/util/cert"
	"k8s.io/kubernetes/pkg/util/wait"
)

type kubeDiscovery struct {
	Deployment *extensions.Deployment
	Secret     *api.Secret
}

const (
	kubeDiscoveryName       = "kube-discovery"
	kubeDiscoverySecretName = "clusterinfo"
)

func encodeKubeDiscoverySecretData(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate) map[string][]byte {
	var (
		data         = map[string][]byte{}
		endpointList = []string{}
		tokenMap     = map[string]string{}
	)

	for _, addr := range s.InitFlags.API.AdvertiseAddrs {
		endpointList = append(endpointList, fmt.Sprintf("https://%s:443", addr.String()))
	}

	tokenMap[s.Secrets.TokenID] = s.Secrets.BearerToken

	data["endpoint-list.json"], _ = json.Marshal(endpointList)
	data["token-map.json"], _ = json.Marshal(tokenMap)
	data["ca.pem"] = certutil.EncodeCertPEM(caCert)

	return data
}

func newKubeDiscoveryPodSpec(s *kubeadmapi.KubeadmConfig) api.PodSpec {
	return api.PodSpec{
		// We have to use host network namespace, as `HostPort`/`HostIP` are Docker's
		// buisness and CNI support isn't quite there yet (except for kubenet)
		// (see https://github.com/kubernetes/kubernetes/issues/31307)
		// TODO update this when #31307 is resolved
		SecurityContext: &api.PodSecurityContext{HostNetwork: true},
		Containers: []api.Container{{
			Name:    kubeDiscoveryName,
			Image:   s.EnvParams["discovery_image"],
			Command: []string{"/usr/local/bin/kube-discovery"},
			VolumeMounts: []api.VolumeMount{{
				Name:      kubeDiscoverySecretName,
				MountPath: "/tmp/secret", // TODO use a shared constant
				ReadOnly:  true,
			}},
			Ports: []api.ContainerPort{
				// TODO when CNI issue (#31307) is resolved, we should consider adding
				// `HostIP: s.API.AdvertiseAddrs[0]`, if there is only one address`
				{Name: "http", ContainerPort: 9898, HostPort: 9898},
			},
		}},
		Volumes: []api.Volume{{
			Name: kubeDiscoverySecretName,
			VolumeSource: api.VolumeSource{
				Secret: &api.SecretVolumeSource{SecretName: kubeDiscoverySecretName},
			}},
		},
	}
}

func newKubeDiscovery(s *kubeadmapi.KubeadmConfig, caCert *x509.Certificate) kubeDiscovery {
	kd := kubeDiscovery{
		Deployment: NewDeployment(kubeDiscoveryName, 1, newKubeDiscoveryPodSpec(s)),
		Secret: &api.Secret{
			ObjectMeta: api.ObjectMeta{Name: kubeDiscoverySecretName},
			Type:       api.SecretTypeOpaque,
			Data:       encodeKubeDiscoverySecretData(s, caCert),
		},
	}

	SetMasterTaintTolerations(&kd.Deployment.Spec.Template.ObjectMeta)
	SetMasterNodeAffinity(&kd.Deployment.Spec.Template.ObjectMeta)

	return kd
}

func CreateDiscoveryDeploymentAndSecret(s *kubeadmapi.KubeadmConfig, client *clientset.Clientset, caCert *x509.Certificate) error {
	kd := newKubeDiscovery(s, caCert)

	if _, err := client.Extensions().Deployments(api.NamespaceSystem).Create(kd.Deployment); err != nil {
		return fmt.Errorf("<master/discovery> failed to create %q deployment [%s]", kubeDiscoveryName, err)
	}
	if _, err := client.Secrets(api.NamespaceSystem).Create(kd.Secret); err != nil {
		return fmt.Errorf("<master/discovery> failed to create %q secret [%s]", kubeDiscoverySecretName, err)
	}

	fmt.Println("<master/discovery> created essential addon: kube-discovery, waiting for it to become ready")

	start := time.Now()
	wait.PollInfinite(apiCallRetryInterval, func() (bool, error) {
		d, err := client.Extensions().Deployments(api.NamespaceSystem).Get(kubeDiscoveryName)
		if err != nil {
			return false, nil
		}
		if d.Status.AvailableReplicas < 1 {
			return false, nil
		}
		return true, nil
	})
	fmt.Printf("<master/discovery> kube-discovery is ready after %f seconds\n", time.Since(start).Seconds())

	return nil
}
<|endoftext|>


<commit_before>package jwthelper

import (
	"fmt"

	"github.com/dgrijalva/jwt-go"
)

// Parser is used to parse JWT token string.
type Parser struct {
	key    interface{}
	parser jwt.Parser
}

// ParserOption represents the option for parsing JWT token string.
// Use option helper functions to set options:
// e.g. ParserUseJSONNumber()
type ParserOption struct {
	f func(p *Parser)
}

var (
	// ErrInvalidParser represents the error of invalid parser.
	ErrInvalidParser = fmt.Errorf("invalid parser")
	// ErrParseClaims represents the error of failed to parse claims.
	ErrParseClaims = fmt.Errorf("failed to parse claims")
	// ErrInvalidToken represents the error of invalid token.
	ErrInvalidToken = fmt.Errorf("invalid token")
)

// ParserUseJSONNumber returns the option for using JSON number.
// It causes the Decoder to unmarshal a number into an interface{} as a Number instead of as a float64.
// After calling Parser.Parse(), the type of number stored in the map[string]interface{} is:
// * float64: flag is false.
// * json.Number: flag is true.
// See https://godoc.org/encoding/json#Decoder.UseNumber
func ParserUseJSONNumber(flag bool) ParserOption {
	return ParserOption{func(p *Parser) {
		p.parser.UseJSONNumber = flag
	}}
}

// NewRSASHAParser news a parser with RSASHA alg.
//
//     Params:
//         key: RSA public PEM key.
//         options: variadic options returned by option helper functions.
//                  e.g. ParserUseJSONNumber.
func NewRSASHAParser(key []byte, options ...ParserOption) *Parser {
	p := &Parser{
		nil,
		jwt.Parser{
			// UseJSONNumber will call encoding/json.Decoder.UseNumber().
			// It causes the Decoder to unmarshal a number into an interface{} as a Number instead of as a float64.
			// See https://godoc.org/encoding/json#Decoder.UseNumber
			UseJSONNumber: true,
			// If populated, only these methods will be considered valid
			// See https://godoc.org/github.com/dgrijalva/jwt-go#Parser
			ValidMethods: []string{
				jwt.SigningMethodRS256.Alg(),
				jwt.SigningMethodRS384.Alg(),
				jwt.SigningMethodRS512.Alg(),
			},
		},
	}

	// Override customized options.
	for _, op := range options {
		op.f(p)
	}

	publicKey, err := jwt.ParseRSAPublicKeyFromPEM(key)
	if err != nil {
		return &Parser{}
	}

	p.key = publicKey
	return p
}

// NewRSASHAParserFromPEMFile news a parser with RSASHA alg from the RSA public PEM file.
//
//     Params:
//         key: RSA public PEM file path.
//         options: variadic options returned by option helper functions.
//                  e.g. ParserUseJSONNumber.
func NewRSASHAParserFromPEMFile(publicPEM string, options ...ParserOption) *Parser {
	key, err := ReadKey(publicPEM)
	if err != nil {
		return &Parser{}
	}

	return NewRSASHAParser(key, options...)
}

// Valid validates the parser.
func (p *Parser) Valid() bool {
	if p.key == nil {
		return false
	}
	return true
}

// Parse parses the signed string and returns the map which stores claims.
//
//     Params:
//         tokenString: token string to be parsed.
//     Return:
//         map stores claims.
//     comments:
//         by default, ParserUseJSONNumber option is true.
//         all numbers will be parsed to json.Number type.
//         Use Number.Int64(), Number.Float64(), Number.String() according to your need.
//         You may get float64 type if set ParserUseJSONNumber option to false when new a parser.
func (p *Parser) Parse(tokenString string) (map[string]interface{}, error) {
	m := map[string]interface{}{}

	if !p.Valid() {
		return m, ErrInvalidParser
	}

	token, err := p.parser.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return p.key, nil
	})

	if err != nil {
		return m, err
	}

	claims, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		return m, ErrParseClaims
	}

	if !token.Valid {
		return m, ErrInvalidToken
	}

	return claims, nil
}
<commit_msg>Add ParseClaims() to parse claims but not verify the signature<commit_after>package jwthelper

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/dgrijalva/jwt-go"
)

// Parser is used to parse JWT token string.
type Parser struct {
	key    interface{}
	parser jwt.Parser
}

// ParserOption represents the option for parsing JWT token string.
// Use option helper functions to set options:
// e.g. ParserUseJSONNumber()
type ParserOption struct {
	f func(p *Parser)
}

var (
	// ErrInvalidParser represents the error of invalid parser.
	ErrInvalidParser = fmt.Errorf("invalid parser")
	// ErrParseClaims represents the error of failed to parse claims.
	ErrParseClaims = fmt.Errorf("failed to parse claims")
	// ErrInvalidToken represents the error of invalid token.
	ErrInvalidToken   = fmt.Errorf("invalid token")
	ErrInvalidPartNum = fmt.Errorf("invalid number of JWT part")
)

// ParserUseJSONNumber returns the option for using JSON number.
// It causes the Decoder to unmarshal a number into an interface{} as a Number instead of as a float64.
// After calling Parser.Parse(), the type of number stored in the map[string]interface{} is:
// * float64: flag is false.
// * json.Number: flag is true.
// See https://godoc.org/encoding/json#Decoder.UseNumber
func ParserUseJSONNumber(flag bool) ParserOption {
	return ParserOption{func(p *Parser) {
		p.parser.UseJSONNumber = flag
	}}
}

// NewRSASHAParser news a parser with RSASHA alg.
//
//     Params:
//         key: RSA public PEM key.
//         options: variadic options returned by option helper functions.
//                  e.g. ParserUseJSONNumber.
func NewRSASHAParser(key []byte, options ...ParserOption) *Parser {
	p := &Parser{
		nil,
		jwt.Parser{
			// UseJSONNumber will call encoding/json.Decoder.UseNumber().
			// It causes the Decoder to unmarshal a number into an interface{} as a Number instead of as a float64.
			// See https://godoc.org/encoding/json#Decoder.UseNumber
			UseJSONNumber: true,
			// If populated, only these methods will be considered valid
			// See https://godoc.org/github.com/dgrijalva/jwt-go#Parser
			ValidMethods: []string{
				jwt.SigningMethodRS256.Alg(),
				jwt.SigningMethodRS384.Alg(),
				jwt.SigningMethodRS512.Alg(),
			},
		},
	}

	// Override customized options.
	for _, op := range options {
		op.f(p)
	}

	publicKey, err := jwt.ParseRSAPublicKeyFromPEM(key)
	if err != nil {
		return &Parser{}
	}

	p.key = publicKey
	return p
}

// NewRSASHAParserFromPEMFile news a parser with RSASHA alg from the RSA public PEM file.
//
//     Params:
//         key: RSA public PEM file path.
//         options: variadic options returned by option helper functions.
//                  e.g. ParserUseJSONNumber.
func NewRSASHAParserFromPEMFile(publicPEM string, options ...ParserOption) *Parser {
	key, err := ReadKey(publicPEM)
	if err != nil {
		return &Parser{}
	}

	return NewRSASHAParser(key, options...)
}

// Valid validates the parser.
func (p *Parser) Valid() bool {
	if p.key == nil {
		return false
	}
	return true
}

// Parse parses the signed string and returns the map which stores claims.
//
//     Params:
//         tokenString: token string to be parsed.
//     Return:
//         map stores claims.
//     comments:
//         by default, ParserUseJSONNumber option is true.
//         all numbers will be parsed to json.Number type.
//         Use Number.Int64(), Number.Float64(), Number.String() according to your need.
//         You may get float64 type if set ParserUseJSONNumber option to false when new a parser.
func (p *Parser) Parse(tokenString string) (map[string]interface{}, error) {
	m := map[string]interface{}{}

	if !p.Valid() {
		return m, ErrInvalidParser
	}

	token, err := p.parser.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return p.key, nil
	})

	if err != nil {
		return m, err
	}

	claims, ok := token.Claims.(jwt.MapClaims)
	if !ok {
		return m, ErrParseClaims
	}

	if !token.Valid {
		return m, ErrInvalidToken
	}

	return claims, nil
}

func ParseClaims(tokenString string) (map[string]interface{}, error) {
	parts := strings.Split(tokenString, ".")
	if len(parts) != 3 {
		return nil, ErrInvalidPartNum
	}

	buf, err := jwt.DecodeSegment(parts[1])
	if err != nil {
		return nil, err
	}

	m := map[string]interface{}{}
	dec := json.NewDecoder(bytes.NewBuffer(buf))
	if err = dec.Decode(&m); err != nil {
		return nil, err
	}

	return m, nil
}
<|endoftext|>


<commit_before><commit_msg>update words<commit_after><|endoftext|>


<commit_before>package client

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/Masterminds/sprig"
	"github.com/kubernetes/helm/pkg/kube"
)

// Installer installs tiller into Kubernetes
//
// See InstallYAML.
type Installer struct {

	// Metadata holds any global metadata attributes for the resources
	Metadata map[string]interface{}

	// Tiller specific metadata
	Tiller map[string]interface{}
}

// NewInstaller creates a new Installer
func NewInstaller() *Installer {
	return &Installer{
		Metadata: map[string]interface{}{},
		Tiller:   map[string]interface{}{},
	}
}

// Install uses kubernetes client to install tiller
//
// Returns the string output received from the operation, and an error if the
// command failed.
func (i *Installer) Install(verbose bool) error {

	var b bytes.Buffer
	err := template.Must(template.New("manifest").Funcs(sprig.TxtFuncMap()).
		Parse(InstallYAML)).
		Execute(&b, i)

	if err != nil {
		return err
	}

	if verbose {
		fmt.Println(b.String())
	}

	return kube.New(nil).Create("helm", &b)
}

// InstallYAML is the installation YAML for DM.
const InstallYAML = `
---{{$namespace := default "helm" .Tiller.Namespace}}
apiVersion: v1
kind: Namespace
metadata:
  labels:
    app: helm
    name: helm-namespace
  name: {{$namespace}}
---
apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    app: helm
    name: tiller
  name: tiller-rc
  namespace: {{$namespace}}
spec:
  replicas: 1
  selector:
    app: helm
    name: tiller
  template:
    metadata:
      labels:
        app: helm
        name: tiller
    spec:
      containers:
      - env:
          - name: DEFAULT_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        image: {{default "gcr.io/kubernetes-helm/tiller:canary" .Tiller.Image}}
        name: tiller
        ports:
        - containerPort: 8080
          name: tiller
        imagePullPolicy: Always
---
`
<commit_msg>fix(tiller): use correct port in rc spec<commit_after>package client

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/Masterminds/sprig"
	"github.com/kubernetes/helm/pkg/kube"
)

// Installer installs tiller into Kubernetes
//
// See InstallYAML.
type Installer struct {

	// Metadata holds any global metadata attributes for the resources
	Metadata map[string]interface{}

	// Tiller specific metadata
	Tiller map[string]interface{}
}

// NewInstaller creates a new Installer
func NewInstaller() *Installer {
	return &Installer{
		Metadata: map[string]interface{}{},
		Tiller:   map[string]interface{}{},
	}
}

// Install uses kubernetes client to install tiller
//
// Returns the string output received from the operation, and an error if the
// command failed.
func (i *Installer) Install(verbose bool) error {

	var b bytes.Buffer
	err := template.Must(template.New("manifest").Funcs(sprig.TxtFuncMap()).
		Parse(InstallYAML)).
		Execute(&b, i)

	if err != nil {
		return err
	}

	if verbose {
		fmt.Println(b.String())
	}

	return kube.New(nil).Create("helm", &b)
}

// InstallYAML is the installation YAML for DM.
const InstallYAML = `
---{{$namespace := default "helm" .Tiller.Namespace}}
apiVersion: v1
kind: Namespace
metadata:
  labels:
    app: helm
    name: helm-namespace
  name: {{$namespace}}
---
apiVersion: v1
kind: ReplicationController
metadata:
  labels:
    app: helm
    name: tiller
  name: tiller-rc
  namespace: {{$namespace}}
spec:
  replicas: 1
  selector:
    app: helm
    name: tiller
  template:
    metadata:
      labels:
        app: helm
        name: tiller
    spec:
      containers:
      - env:
          - name: DEFAULT_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        image: {{default "gcr.io/kubernetes-helm/tiller:canary" .Tiller.Image}}
        name: tiller
        ports:
        - containerPort: 44134
          name: tiller
        imagePullPolicy: Always
---
`
<|endoftext|>


<commit_before>// 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 httputil

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// One of the copies, say from b to r2, could be avoided by using a more
// elaborate trick where the other copy is made during Request/Response.Write.
// This would complicate things too much, given that these functions are for
// debugging only.
func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
	var buf bytes.Buffer
	if _, err = buf.ReadFrom(b); err != nil {
		return nil, nil, err
	}
	if err = b.Close(); err != nil {
		return nil, nil, err
	}
	return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewBuffer(buf.Bytes())), nil
}

// dumpConn is a net.Conn which writes to Writer and reads from Reader
type dumpConn struct {
	io.Writer
	io.Reader
}

func (c *dumpConn) Close() error                       { return nil }
func (c *dumpConn) LocalAddr() net.Addr                { return nil }
func (c *dumpConn) RemoteAddr() net.Addr               { return nil }
func (c *dumpConn) SetDeadline(t time.Time) error      { return nil }
func (c *dumpConn) SetReadDeadline(t time.Time) error  { return nil }
func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }

// DumpRequestOut is like DumpRequest but includes
// headers that the standard http.Transport adds,
// such as User-Agent.
func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
	save := req.Body
	if !body || req.Body == nil {
		req.Body = nil
	} else {
		var err error
		save, req.Body, err = drainBody(req.Body)
		if err != nil {
			return nil, err
		}
	}

	// Since we're using the actual Transport code to write the request,
	// switch to http so the Transport doesn't try to do an SSL
	// negotiation with our dumpConn and its bytes.Buffer & pipe.
	// The wire format for https and http are the same, anyway.
	reqSend := req
	if req.URL.Scheme == "https" {
		reqSend = new(http.Request)
		*reqSend = *req
		reqSend.URL = new(url.URL)
		*reqSend.URL = *req.URL
		reqSend.URL.Scheme = "http"
	}

	// Use the actual Transport code to record what we would send
	// on the wire, but not using TCP.  Use a Transport with a
	// customer dialer that returns a fake net.Conn that waits
	// for the full input (and recording it), and then responds
	// with a dummy response.
	var buf bytes.Buffer // records the output
	pr, pw := io.Pipe()
	dr := &delegateReader{c: make(chan io.Reader)}
	// Wait for the request before replying with a dummy response:
	go func() {
		http.ReadRequest(bufio.NewReader(pr))
		dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\n\r\n")
	}()

	t := &http.Transport{
		Dial: func(net, addr string) (net.Conn, error) {
			return &dumpConn{io.MultiWriter(pw, &buf), dr}, nil
		},
	}

	_, err := t.RoundTrip(reqSend)

	req.Body = save
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// delegateReader is a reader that delegates to another reader,
// once it arrives on a channel.
type delegateReader struct {
	c chan io.Reader
	r io.Reader // nil until received from c
}

func (r *delegateReader) Read(p []byte) (int, error) {
	if r.r == nil {
		r.r = <-r.c
	}
	return r.r.Read(p)
}

// Return value if nonempty, def otherwise.
func valueOrDefault(value, def string) string {
	if value != "" {
		return value
	}
	return def
}

var reqWriteExcludeHeaderDump = map[string]bool{
	"Host":              true, // not in Header map anyway
	"Content-Length":    true,
	"Transfer-Encoding": true,
	"Trailer":           true,
}

// dumpAsReceived writes req to w in the form as it was received, or
// at least as accurately as possible from the information retained in
// the request.
func dumpAsReceived(req *http.Request, w io.Writer) error {
	return nil
}

// DumpRequest returns the as-received wire representation of req,
// optionally including the request body, for debugging.
// DumpRequest is semantically a no-op, but in order to
// dump the body, it reads the body data into memory and
// changes req.Body to refer to the in-memory copy.
// The documentation for http.Request.Write details which fields
// of req are used.
func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
	save := req.Body
	if !body || req.Body == nil {
		req.Body = nil
	} else {
		save, req.Body, err = drainBody(req.Body)
		if err != nil {
			return
		}
	}

	var b bytes.Buffer

	fmt.Fprintf(&b, "%s %s HTTP/%d.%d\r\n", valueOrDefault(req.Method, "GET"),
		req.URL.RequestURI(), req.ProtoMajor, req.ProtoMinor)

	host := req.Host
	if host == "" && req.URL != nil {
		host = req.URL.Host
	}
	if host != "" {
		fmt.Fprintf(&b, "Host: %s\r\n", host)
	}

	chunked := len(req.TransferEncoding) > 0 && req.TransferEncoding[0] == "chunked"
	if len(req.TransferEncoding) > 0 {
		fmt.Fprintf(&b, "Transfer-Encoding: %s\r\n", strings.Join(req.TransferEncoding, ","))
	}
	if req.Close {
		fmt.Fprintf(&b, "Connection: close\r\n")
	}

	err = req.Header.WriteSubset(&b, reqWriteExcludeHeaderDump)
	if err != nil {
		return
	}

	io.WriteString(&b, "\r\n")

	if req.Body != nil {
		var dest io.Writer = &b
		if chunked {
			dest = NewChunkedWriter(dest)
		}
		_, err = io.Copy(dest, req.Body)
		if chunked {
			dest.(io.Closer).Close()
			io.WriteString(&b, "\r\n")
		}
	}

	req.Body = save
	if err != nil {
		return
	}
	dump = b.Bytes()
	return
}

// DumpResponse is like DumpRequest but dumps a response.
func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
	var b bytes.Buffer
	save := resp.Body
	savecl := resp.ContentLength
	if !body || resp.Body == nil {
		resp.Body = nil
		resp.ContentLength = 0
	} else {
		save, resp.Body, err = drainBody(resp.Body)
		if err != nil {
			return
		}
	}
	err = resp.Write(&b)
	resp.Body = save
	resp.ContentLength = savecl
	if err != nil {
		return
	}
	dump = b.Bytes()
	return
}
<commit_msg>net/http/httputil: fix typo in comment.<commit_after>// 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 httputil

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// One of the copies, say from b to r2, could be avoided by using a more
// elaborate trick where the other copy is made during Request/Response.Write.
// This would complicate things too much, given that these functions are for
// debugging only.
func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
	var buf bytes.Buffer
	if _, err = buf.ReadFrom(b); err != nil {
		return nil, nil, err
	}
	if err = b.Close(); err != nil {
		return nil, nil, err
	}
	return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewBuffer(buf.Bytes())), nil
}

// dumpConn is a net.Conn which writes to Writer and reads from Reader
type dumpConn struct {
	io.Writer
	io.Reader
}

func (c *dumpConn) Close() error                       { return nil }
func (c *dumpConn) LocalAddr() net.Addr                { return nil }
func (c *dumpConn) RemoteAddr() net.Addr               { return nil }
func (c *dumpConn) SetDeadline(t time.Time) error      { return nil }
func (c *dumpConn) SetReadDeadline(t time.Time) error  { return nil }
func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }

// DumpRequestOut is like DumpRequest but includes
// headers that the standard http.Transport adds,
// such as User-Agent.
func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
	save := req.Body
	if !body || req.Body == nil {
		req.Body = nil
	} else {
		var err error
		save, req.Body, err = drainBody(req.Body)
		if err != nil {
			return nil, err
		}
	}

	// Since we're using the actual Transport code to write the request,
	// switch to http so the Transport doesn't try to do an SSL
	// negotiation with our dumpConn and its bytes.Buffer & pipe.
	// The wire format for https and http are the same, anyway.
	reqSend := req
	if req.URL.Scheme == "https" {
		reqSend = new(http.Request)
		*reqSend = *req
		reqSend.URL = new(url.URL)
		*reqSend.URL = *req.URL
		reqSend.URL.Scheme = "http"
	}

	// Use the actual Transport code to record what we would send
	// on the wire, but not using TCP.  Use a Transport with a
	// custom dialer that returns a fake net.Conn that waits
	// for the full input (and recording it), and then responds
	// with a dummy response.
	var buf bytes.Buffer // records the output
	pr, pw := io.Pipe()
	dr := &delegateReader{c: make(chan io.Reader)}
	// Wait for the request before replying with a dummy response:
	go func() {
		http.ReadRequest(bufio.NewReader(pr))
		dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\n\r\n")
	}()

	t := &http.Transport{
		Dial: func(net, addr string) (net.Conn, error) {
			return &dumpConn{io.MultiWriter(pw, &buf), dr}, nil
		},
	}

	_, err := t.RoundTrip(reqSend)

	req.Body = save
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// delegateReader is a reader that delegates to another reader,
// once it arrives on a channel.
type delegateReader struct {
	c chan io.Reader
	r io.Reader // nil until received from c
}

func (r *delegateReader) Read(p []byte) (int, error) {
	if r.r == nil {
		r.r = <-r.c
	}
	return r.r.Read(p)
}

// Return value if nonempty, def otherwise.
func valueOrDefault(value, def string) string {
	if value != "" {
		return value
	}
	return def
}

var reqWriteExcludeHeaderDump = map[string]bool{
	"Host":              true, // not in Header map anyway
	"Content-Length":    true,
	"Transfer-Encoding": true,
	"Trailer":           true,
}

// dumpAsReceived writes req to w in the form as it was received, or
// at least as accurately as possible from the information retained in
// the request.
func dumpAsReceived(req *http.Request, w io.Writer) error {
	return nil
}

// DumpRequest returns the as-received wire representation of req,
// optionally including the request body, for debugging.
// DumpRequest is semantically a no-op, but in order to
// dump the body, it reads the body data into memory and
// changes req.Body to refer to the in-memory copy.
// The documentation for http.Request.Write details which fields
// of req are used.
func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
	save := req.Body
	if !body || req.Body == nil {
		req.Body = nil
	} else {
		save, req.Body, err = drainBody(req.Body)
		if err != nil {
			return
		}
	}

	var b bytes.Buffer

	fmt.Fprintf(&b, "%s %s HTTP/%d.%d\r\n", valueOrDefault(req.Method, "GET"),
		req.URL.RequestURI(), req.ProtoMajor, req.ProtoMinor)

	host := req.Host
	if host == "" && req.URL != nil {
		host = req.URL.Host
	}
	if host != "" {
		fmt.Fprintf(&b, "Host: %s\r\n", host)
	}

	chunked := len(req.TransferEncoding) > 0 && req.TransferEncoding[0] == "chunked"
	if len(req.TransferEncoding) > 0 {
		fmt.Fprintf(&b, "Transfer-Encoding: %s\r\n", strings.Join(req.TransferEncoding, ","))
	}
	if req.Close {
		fmt.Fprintf(&b, "Connection: close\r\n")
	}

	err = req.Header.WriteSubset(&b, reqWriteExcludeHeaderDump)
	if err != nil {
		return
	}

	io.WriteString(&b, "\r\n")

	if req.Body != nil {
		var dest io.Writer = &b
		if chunked {
			dest = NewChunkedWriter(dest)
		}
		_, err = io.Copy(dest, req.Body)
		if chunked {
			dest.(io.Closer).Close()
			io.WriteString(&b, "\r\n")
		}
	}

	req.Body = save
	if err != nil {
		return
	}
	dump = b.Bytes()
	return
}

// DumpResponse is like DumpRequest but dumps a response.
func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
	var b bytes.Buffer
	save := resp.Body
	savecl := resp.ContentLength
	if !body || resp.Body == nil {
		resp.Body = nil
		resp.ContentLength = 0
	} else {
		save, resp.Body, err = drainBody(resp.Body)
		if err != nil {
			return
		}
	}
	err = resp.Write(&b)
	resp.Body = save
	resp.ContentLength = savecl
	if err != nil {
		return
	}
	dump = b.Bytes()
	return
}
<|endoftext|>