PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Godeps/_workspace/src/google.golang.org/appengine/internal/api.go

https://github.com/ironcladlou/kubernetes
Go | 589 lines | 464 code | 70 blank | 55 comment | 97 complexity | 3a41e16894a2edafed2be237d29d4b62 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, LGPL-3.0, Apache-2.0, JSON, BSD-2-Clause
  1. // Copyright 2011 Google Inc. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package internal
  5. import (
  6. "bytes"
  7. "fmt"
  8. "io/ioutil"
  9. "log"
  10. "net"
  11. "net/http"
  12. "net/url"
  13. "os"
  14. "runtime"
  15. "strconv"
  16. "strings"
  17. "sync"
  18. "sync/atomic"
  19. "time"
  20. "github.com/golang/protobuf/proto"
  21. basepb "google.golang.org/appengine/internal/base"
  22. logpb "google.golang.org/appengine/internal/log"
  23. remotepb "google.golang.org/appengine/internal/remote_api"
  24. )
  25. const (
  26. apiPath = "/rpc_http"
  27. )
  28. var (
  29. // Incoming headers.
  30. ticketHeader = http.CanonicalHeaderKey("X-AppEngine-API-Ticket")
  31. dapperHeader = http.CanonicalHeaderKey("X-Google-DapperTraceInfo")
  32. defNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Default-Namespace")
  33. curNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Current-Namespace")
  34. userIPHeader = http.CanonicalHeaderKey("X-AppEngine-User-IP")
  35. remoteAddrHeader = http.CanonicalHeaderKey("X-AppEngine-Remote-Addr")
  36. // Outgoing headers.
  37. apiEndpointHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Endpoint")
  38. apiEndpointHeaderValue = []string{"app-engine-apis"}
  39. apiMethodHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Method")
  40. apiMethodHeaderValue = []string{"/VMRemoteAPI.CallRemoteAPI"}
  41. apiDeadlineHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Deadline")
  42. apiContentType = http.CanonicalHeaderKey("Content-Type")
  43. apiContentTypeValue = []string{"application/octet-stream"}
  44. logFlushHeader = http.CanonicalHeaderKey("X-AppEngine-Log-Flush-Count")
  45. apiHTTPClient = &http.Client{
  46. Transport: &http.Transport{
  47. Proxy: http.ProxyFromEnvironment,
  48. Dial: limitDial,
  49. },
  50. }
  51. )
  52. func apiHost() string {
  53. host, port := "appengine.googleapis.com", "10001"
  54. if h := os.Getenv("API_HOST"); h != "" {
  55. host = h
  56. }
  57. if p := os.Getenv("API_PORT"); p != "" {
  58. port = p
  59. }
  60. return host + ":" + port
  61. }
  62. func handleHTTP(w http.ResponseWriter, r *http.Request) {
  63. c := &context{
  64. req: r,
  65. outHeader: w.Header(),
  66. }
  67. stopFlushing := make(chan int)
  68. ctxs.Lock()
  69. ctxs.m[r] = c
  70. ctxs.Unlock()
  71. defer func() {
  72. ctxs.Lock()
  73. delete(ctxs.m, r)
  74. ctxs.Unlock()
  75. }()
  76. // Patch up RemoteAddr so it looks reasonable.
  77. if addr := r.Header.Get(userIPHeader); addr != "" {
  78. r.RemoteAddr = addr
  79. } else if addr = r.Header.Get(remoteAddrHeader); addr != "" {
  80. r.RemoteAddr = addr
  81. } else {
  82. // Should not normally reach here, but pick a sensible default anyway.
  83. r.RemoteAddr = "127.0.0.1"
  84. }
  85. // The address in the headers will most likely be of these forms:
  86. // 123.123.123.123
  87. // 2001:db8::1
  88. // net/http.Request.RemoteAddr is specified to be in "IP:port" form.
  89. if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil {
  90. // Assume the remote address is only a host; add a default port.
  91. r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80")
  92. }
  93. // Start goroutine responsible for flushing app logs.
  94. // This is done after adding c to ctx.m (and stopped before removing it)
  95. // because flushing logs requires making an API call.
  96. go c.logFlusher(stopFlushing)
  97. executeRequestSafely(c, r)
  98. c.outHeader = nil // make sure header changes aren't respected any more
  99. stopFlushing <- 1 // any logging beyond this point will be dropped
  100. // Flush any pending logs asynchronously.
  101. c.pendingLogs.Lock()
  102. flushes := c.pendingLogs.flushes
  103. if len(c.pendingLogs.lines) > 0 {
  104. flushes++
  105. }
  106. c.pendingLogs.Unlock()
  107. go c.flushLog(false)
  108. w.Header().Set(logFlushHeader, strconv.Itoa(flushes))
  109. // Avoid nil Write call if c.Write is never called.
  110. if c.outCode != 0 {
  111. w.WriteHeader(c.outCode)
  112. }
  113. if c.outBody != nil {
  114. w.Write(c.outBody)
  115. }
  116. }
  117. func executeRequestSafely(c *context, r *http.Request) {
  118. defer func() {
  119. if x := recover(); x != nil {
  120. c.logf(4, "%s", renderPanic(x)) // 4 == critical
  121. }
  122. }()
  123. http.DefaultServeMux.ServeHTTP(c, r)
  124. }
  125. func renderPanic(x interface{}) string {
  126. buf := make([]byte, 16<<10) // 16 KB should be plenty
  127. buf = buf[:runtime.Stack(buf, false)]
  128. // Remove the first few stack frames:
  129. // this func
  130. // the recover closure in the caller
  131. // That will root the stack trace at the site of the panic.
  132. const (
  133. skipStart = "internal.renderPanic"
  134. skipFrames = 2
  135. )
  136. start := bytes.Index(buf, []byte(skipStart))
  137. p := start
  138. for i := 0; i < skipFrames*2 && p+1 < len(buf); i++ {
  139. p = bytes.IndexByte(buf[p+1:], '\n') + p + 1
  140. if p < 0 {
  141. break
  142. }
  143. }
  144. if p >= 0 {
  145. // buf[start:p+1] is the block to remove.
  146. // Copy buf[p+1:] over buf[start:] and shrink buf.
  147. copy(buf[start:], buf[p+1:])
  148. buf = buf[:len(buf)-(p+1-start)]
  149. }
  150. // Add panic heading.
  151. head := fmt.Sprintf("panic: %v\n\n", x)
  152. if len(head) > len(buf) {
  153. // Extremely unlikely to happen.
  154. return head
  155. }
  156. copy(buf[len(head):], buf)
  157. copy(buf, head)
  158. return string(buf)
  159. }
  160. var ctxs = struct {
  161. sync.Mutex
  162. m map[*http.Request]*context
  163. bg *context // background context, lazily initialized
  164. }{
  165. m: make(map[*http.Request]*context),
  166. }
  167. // context represents the context of an in-flight HTTP request.
  168. // It implements the appengine.Context and http.ResponseWriter interfaces.
  169. type context struct {
  170. req *http.Request
  171. outCode int
  172. outHeader http.Header
  173. outBody []byte
  174. pendingLogs struct {
  175. sync.Mutex
  176. lines []*logpb.UserAppLogLine
  177. flushes int
  178. }
  179. }
  180. func NewContext(req *http.Request) *context {
  181. ctxs.Lock()
  182. c := ctxs.m[req]
  183. ctxs.Unlock()
  184. if c == nil {
  185. // Someone passed in an http.Request that is not in-flight.
  186. // We panic here rather than panicking at a later point
  187. // so that stack traces will be more sensible.
  188. log.Panic("appengine: NewContext passed an unknown http.Request")
  189. }
  190. return c
  191. }
  192. func BackgroundContext() *context {
  193. ctxs.Lock()
  194. defer ctxs.Unlock()
  195. if ctxs.bg != nil {
  196. return ctxs.bg
  197. }
  198. // Compute background security ticket.
  199. appID := partitionlessAppID()
  200. escAppID := strings.Replace(strings.Replace(appID, ":", "_", -1), ".", "_", -1)
  201. majVersion := VersionID()
  202. if i := strings.Index(majVersion, "_"); i >= 0 {
  203. majVersion = majVersion[:i]
  204. }
  205. ticket := fmt.Sprintf("%s/%s.%s.%s", escAppID, ModuleName(), majVersion, InstanceID())
  206. ctxs.bg = &context{
  207. req: &http.Request{
  208. Header: http.Header{
  209. ticketHeader: []string{ticket},
  210. },
  211. },
  212. }
  213. // TODO(dsymonds): Wire up the shutdown handler to do a final flush.
  214. go ctxs.bg.logFlusher(make(chan int))
  215. return ctxs.bg
  216. }
  217. var errTimeout = &CallError{
  218. Detail: "Deadline exceeded",
  219. Code: int32(remotepb.RpcError_CANCELLED),
  220. Timeout: true,
  221. }
  222. func (c *context) Header() http.Header { return c.outHeader }
  223. // Copied from $GOROOT/src/pkg/net/http/transfer.go. Some response status
  224. // codes do not permit a response body (nor response entity headers such as
  225. // Content-Length, Content-Type, etc).
  226. func bodyAllowedForStatus(status int) bool {
  227. switch {
  228. case status >= 100 && status <= 199:
  229. return false
  230. case status == 204:
  231. return false
  232. case status == 304:
  233. return false
  234. }
  235. return true
  236. }
  237. func (c *context) Write(b []byte) (int, error) {
  238. if c.outCode == 0 {
  239. c.WriteHeader(http.StatusOK)
  240. }
  241. if len(b) > 0 && !bodyAllowedForStatus(c.outCode) {
  242. return 0, http.ErrBodyNotAllowed
  243. }
  244. c.outBody = append(c.outBody, b...)
  245. return len(b), nil
  246. }
  247. func (c *context) WriteHeader(code int) {
  248. if c.outCode != 0 {
  249. c.Errorf("WriteHeader called multiple times on request.")
  250. return
  251. }
  252. c.outCode = code
  253. }
  254. func (c *context) post(body []byte, timeout time.Duration) (b []byte, err error) {
  255. dst := apiHost()
  256. hreq := &http.Request{
  257. Method: "POST",
  258. URL: &url.URL{
  259. Scheme: "http",
  260. Host: dst,
  261. Path: apiPath,
  262. },
  263. Header: http.Header{
  264. apiEndpointHeader: apiEndpointHeaderValue,
  265. apiMethodHeader: apiMethodHeaderValue,
  266. apiContentType: apiContentTypeValue,
  267. apiDeadlineHeader: []string{strconv.FormatFloat(timeout.Seconds(), 'f', -1, 64)},
  268. },
  269. Body: ioutil.NopCloser(bytes.NewReader(body)),
  270. ContentLength: int64(len(body)),
  271. Host: dst,
  272. }
  273. if info := c.req.Header.Get(dapperHeader); info != "" {
  274. hreq.Header.Set(dapperHeader, info)
  275. }
  276. tr := apiHTTPClient.Transport.(*http.Transport)
  277. var timedOut int32 // atomic; set to 1 if timed out
  278. t := time.AfterFunc(timeout, func() {
  279. atomic.StoreInt32(&timedOut, 1)
  280. tr.CancelRequest(hreq)
  281. })
  282. defer t.Stop()
  283. defer func() {
  284. // Check if timeout was exceeded.
  285. if atomic.LoadInt32(&timedOut) != 0 {
  286. err = errTimeout
  287. }
  288. }()
  289. hresp, err := apiHTTPClient.Do(hreq)
  290. if err != nil {
  291. return nil, &CallError{
  292. Detail: fmt.Sprintf("service bridge HTTP failed: %v", err),
  293. Code: int32(remotepb.RpcError_UNKNOWN),
  294. }
  295. }
  296. defer hresp.Body.Close()
  297. hrespBody, err := ioutil.ReadAll(hresp.Body)
  298. if hresp.StatusCode != 200 {
  299. return nil, &CallError{
  300. Detail: fmt.Sprintf("service bridge returned HTTP %d (%q)", hresp.StatusCode, hrespBody),
  301. Code: int32(remotepb.RpcError_UNKNOWN),
  302. }
  303. }
  304. if err != nil {
  305. return nil, &CallError{
  306. Detail: fmt.Sprintf("service bridge response bad: %v", err),
  307. Code: int32(remotepb.RpcError_UNKNOWN),
  308. }
  309. }
  310. return hrespBody, nil
  311. }
  312. var virtualMethodHeaders = map[string]string{
  313. "GetNamespace": curNamespaceHeader,
  314. "GetDefaultNamespace": defNamespaceHeader,
  315. "user:Email": http.CanonicalHeaderKey("X-AppEngine-User-Email"),
  316. "user:AuthDomain": http.CanonicalHeaderKey("X-AppEngine-Auth-Domain"),
  317. "user:ID": http.CanonicalHeaderKey("X-AppEngine-User-Id"),
  318. "user:IsAdmin": http.CanonicalHeaderKey("X-AppEngine-User-Is-Admin"),
  319. "user:FederatedIdentity": http.CanonicalHeaderKey("X-AppEngine-Federated-Identity"),
  320. "user:FederatedProvider": http.CanonicalHeaderKey("X-AppEngine-Federated-Provider"),
  321. }
  322. func (c *context) Call(service, method string, in, out proto.Message, opts *CallOptions) error {
  323. if service == "__go__" {
  324. if hdr, ok := virtualMethodHeaders[method]; ok {
  325. out.(*basepb.StringProto).Value = proto.String(c.req.Header.Get(hdr))
  326. return nil
  327. }
  328. }
  329. // Default RPC timeout is 5s.
  330. timeout := 5 * time.Second
  331. if opts != nil && opts.Timeout > 0 {
  332. timeout = opts.Timeout
  333. }
  334. data, err := proto.Marshal(in)
  335. if err != nil {
  336. return err
  337. }
  338. ticket := c.req.Header.Get(ticketHeader)
  339. req := &remotepb.Request{
  340. ServiceName: &service,
  341. Method: &method,
  342. Request: data,
  343. RequestId: &ticket,
  344. }
  345. hreqBody, err := proto.Marshal(req)
  346. if err != nil {
  347. return err
  348. }
  349. hrespBody, err := c.post(hreqBody, timeout)
  350. if err != nil {
  351. return err
  352. }
  353. res := &remotepb.Response{}
  354. if err := proto.Unmarshal(hrespBody, res); err != nil {
  355. return err
  356. }
  357. if res.RpcError != nil {
  358. ce := &CallError{
  359. Detail: res.RpcError.GetDetail(),
  360. Code: *res.RpcError.Code,
  361. }
  362. switch remotepb.RpcError_ErrorCode(ce.Code) {
  363. case remotepb.RpcError_CANCELLED, remotepb.RpcError_DEADLINE_EXCEEDED:
  364. ce.Timeout = true
  365. }
  366. return ce
  367. }
  368. if res.ApplicationError != nil {
  369. return &APIError{
  370. Service: *req.ServiceName,
  371. Detail: res.ApplicationError.GetDetail(),
  372. Code: *res.ApplicationError.Code,
  373. }
  374. }
  375. if res.Exception != nil || res.JavaException != nil {
  376. // This shouldn't happen, but let's be defensive.
  377. return &CallError{
  378. Detail: "service bridge returned exception",
  379. Code: int32(remotepb.RpcError_UNKNOWN),
  380. }
  381. }
  382. return proto.Unmarshal(res.Response, out)
  383. }
  384. func (c *context) Request() interface{} {
  385. return c.req
  386. }
  387. func (c *context) addLogLine(ll *logpb.UserAppLogLine) {
  388. // Truncate long log lines.
  389. // TODO(dsymonds): Check if this is still necessary.
  390. const lim = 8 << 10
  391. if len(*ll.Message) > lim {
  392. suffix := fmt.Sprintf("...(length %d)", len(*ll.Message))
  393. ll.Message = proto.String((*ll.Message)[:lim-len(suffix)] + suffix)
  394. }
  395. c.pendingLogs.Lock()
  396. c.pendingLogs.lines = append(c.pendingLogs.lines, ll)
  397. c.pendingLogs.Unlock()
  398. }
  399. var logLevelName = map[int64]string{
  400. 0: "DEBUG",
  401. 1: "INFO",
  402. 2: "WARNING",
  403. 3: "ERROR",
  404. 4: "CRITICAL",
  405. }
  406. func (c *context) logf(level int64, format string, args ...interface{}) {
  407. s := fmt.Sprintf(format, args...)
  408. s = strings.TrimRight(s, "\n") // Remove any trailing newline characters.
  409. c.addLogLine(&logpb.UserAppLogLine{
  410. TimestampUsec: proto.Int64(time.Now().UnixNano() / 1e3),
  411. Level: &level,
  412. Message: &s,
  413. })
  414. log.Print(logLevelName[level] + ": " + s)
  415. }
  416. func (c *context) Debugf(format string, args ...interface{}) { c.logf(0, format, args...) }
  417. func (c *context) Infof(format string, args ...interface{}) { c.logf(1, format, args...) }
  418. func (c *context) Warningf(format string, args ...interface{}) { c.logf(2, format, args...) }
  419. func (c *context) Errorf(format string, args ...interface{}) { c.logf(3, format, args...) }
  420. func (c *context) Criticalf(format string, args ...interface{}) { c.logf(4, format, args...) }
  421. // FullyQualifiedAppID returns the fully-qualified application ID.
  422. // This may contain a partition prefix (e.g. "s~" for High Replication apps),
  423. // or a domain prefix (e.g. "example.com:").
  424. func (c *context) FullyQualifiedAppID() string { return fullyQualifiedAppID() }
  425. // flushLog attempts to flush any pending logs to the appserver.
  426. // It should not be called concurrently.
  427. func (c *context) flushLog(force bool) (flushed bool) {
  428. c.pendingLogs.Lock()
  429. // Grab up to 30 MB. We can get away with up to 32 MB, but let's be cautious.
  430. n, rem := 0, 30<<20
  431. for ; n < len(c.pendingLogs.lines); n++ {
  432. ll := c.pendingLogs.lines[n]
  433. // Each log line will require about 3 bytes of overhead.
  434. nb := proto.Size(ll) + 3
  435. if nb > rem {
  436. break
  437. }
  438. rem -= nb
  439. }
  440. lines := c.pendingLogs.lines[:n]
  441. c.pendingLogs.lines = c.pendingLogs.lines[n:]
  442. c.pendingLogs.Unlock()
  443. if len(lines) == 0 && !force {
  444. // Nothing to flush.
  445. return false
  446. }
  447. rescueLogs := false
  448. defer func() {
  449. if rescueLogs {
  450. c.pendingLogs.Lock()
  451. c.pendingLogs.lines = append(lines, c.pendingLogs.lines...)
  452. c.pendingLogs.Unlock()
  453. }
  454. }()
  455. buf, err := proto.Marshal(&logpb.UserAppLogGroup{
  456. LogLine: lines,
  457. })
  458. if err != nil {
  459. log.Printf("internal.flushLog: marshaling UserAppLogGroup: %v", err)
  460. rescueLogs = true
  461. return false
  462. }
  463. req := &logpb.FlushRequest{
  464. Logs: buf,
  465. }
  466. res := &basepb.VoidProto{}
  467. c.pendingLogs.Lock()
  468. c.pendingLogs.flushes++
  469. c.pendingLogs.Unlock()
  470. if err := c.Call("logservice", "Flush", req, res, nil); err != nil {
  471. log.Printf("internal.flushLog: Flush RPC: %v", err)
  472. rescueLogs = true
  473. return false
  474. }
  475. return true
  476. }
  477. const (
  478. // Log flushing parameters.
  479. flushInterval = 1 * time.Second
  480. forceFlushInterval = 60 * time.Second
  481. )
  482. func (c *context) logFlusher(stop <-chan int) {
  483. lastFlush := time.Now()
  484. tick := time.NewTicker(flushInterval)
  485. for {
  486. select {
  487. case <-stop:
  488. // Request finished.
  489. tick.Stop()
  490. return
  491. case <-tick.C:
  492. force := time.Now().Sub(lastFlush) > forceFlushInterval
  493. if c.flushLog(force) {
  494. lastFlush = time.Now()
  495. }
  496. }
  497. }
  498. }
  499. func ContextForTesting(req *http.Request) *context {
  500. return &context{req: req}
  501. }
  502. // caller is a subset of appengine.Context.
  503. type caller interface {
  504. Call(service, method string, in, out proto.Message, opts *CallOptions) error
  505. }
  506. var virtualOpts = &CallOptions{
  507. // Virtual API calls should happen nearly instantaneously.
  508. Timeout: 1 * time.Millisecond,
  509. }
  510. // VirtAPI invokes a virtual API call for the __go__ service.
  511. // It is for methods that accept a VoidProto and return a StringProto.
  512. // It returns an empty string if the call fails.
  513. func VirtAPI(c caller, method string) string {
  514. s := &basepb.StringProto{}
  515. if err := c.Call("__go__", method, &basepb.VoidProto{}, s, virtualOpts); err != nil {
  516. log.Printf("/__go__.%s failed: %v", method, err)
  517. }
  518. return s.GetValue()
  519. }