============================ supporting methods and misc ============================ forward control plane request to the current primary proxy return: forf (forwarded or failed) where forf = true means exactly that: forwarded or failed
(w http.ResponseWriter, r *http.Request, msg *apc.ActionMsg, s string, origBody ...[]byte)
| 1725 | // forward control plane request to the current primary proxy |
| 1726 | // return: forf (forwarded or failed) where forf = true means exactly that: forwarded or failed |
| 1727 | func (p *proxy) forwardCP(w http.ResponseWriter, r *http.Request, msg *apc.ActionMsg, |
| 1728 | s string, origBody ...[]byte) (forf bool) { |
| 1729 | var ( |
| 1730 | body []byte |
| 1731 | smap = p.owner.smap.get() |
| 1732 | ) |
| 1733 | if !smap.isValid() { |
| 1734 | errmsg := fmt.Sprintf("%s must be starting up: cannot execute", p.si) |
| 1735 | if msg != nil { |
| 1736 | p.writeErrStatusf(w, r, http.StatusServiceUnavailable, "%s %s: %s", errmsg, msg.Action, s) |
| 1737 | } else { |
| 1738 | p.writeErrStatusf(w, r, http.StatusServiceUnavailable, "%s %q", errmsg, s) |
| 1739 | } |
| 1740 | return true |
| 1741 | } |
| 1742 | if p.inPrimaryTransition.Load() { |
| 1743 | p.writeErrStatusf(w, r, http.StatusServiceUnavailable, |
| 1744 | "%s is in transition, cannot process the request", p.si) |
| 1745 | return true |
| 1746 | } |
| 1747 | if smap.isPrimary(p.si) { |
| 1748 | return |
| 1749 | } |
| 1750 | // We must **not** send any request body when doing HEAD request. |
| 1751 | // Otherwise, the request can be rejected and terminated. |
| 1752 | if r.Method != http.MethodHead { |
| 1753 | if len(origBody) > 0 && len(origBody[0]) > 0 { |
| 1754 | body = origBody[0] |
| 1755 | } else if msg != nil { |
| 1756 | body = cos.MustMarshal(msg) |
| 1757 | } |
| 1758 | } |
| 1759 | primary := &p.rproxy.primary |
| 1760 | primary.Lock() |
| 1761 | if primary.url != smap.Primary.PubNet.URL { |
| 1762 | primary.url = smap.Primary.PubNet.URL |
| 1763 | uparsed, err := url.Parse(smap.Primary.PubNet.URL) |
| 1764 | cos.AssertNoErr(err) |
| 1765 | cfg := cmn.GCO.Get() |
| 1766 | primary.rp = httputil.NewSingleHostReverseProxy(uparsed) |
| 1767 | primary.rp.Transport = cmn.NewTransport(cmn.TransportArgs{ |
| 1768 | UseHTTPS: cfg.Net.HTTP.UseHTTPS, |
| 1769 | SkipVerify: cfg.Net.HTTP.SkipVerify, |
| 1770 | }) |
| 1771 | primary.rp.ErrorHandler = p.rpErrHandler |
| 1772 | } |
| 1773 | primary.Unlock() |
| 1774 | if len(body) > 0 { |
| 1775 | debug.AssertFunc(func() bool { |
| 1776 | l, _ := io.Copy(io.Discard, r.Body) |
| 1777 | return l == 0 |
| 1778 | }) |
| 1779 | |
| 1780 | r.Body = io.NopCloser(bytes.NewBuffer(body)) |
| 1781 | r.ContentLength = int64(len(body)) // Directly setting `Content-Length` header. |
| 1782 | } |
| 1783 | if msg != nil { |
| 1784 | glog.Infof("%s: forwarding \"%s:%s\" to the primary %s", p, msg.Action, s, smap.Primary.StringEx()) |
no test coverage detected