mirror of
https://gitee.com/IrisVega/frp.git
synced 2024-11-01 22:31:29 +08:00
Merge pull request #786 from fatedier/header
support setting headers in http request
This commit is contained in:
commit
cf4136fe99
22
README.md
22
README.md
@ -36,6 +36,7 @@ frp is a fast reverse proxy to help you expose a local server behind a NAT or fi
|
|||||||
* [Support KCP Protocol](#support-kcp-protocol)
|
* [Support KCP Protocol](#support-kcp-protocol)
|
||||||
* [Connection Pool](#connection-pool)
|
* [Connection Pool](#connection-pool)
|
||||||
* [Rewriting the Host Header](#rewriting-the-host-header)
|
* [Rewriting the Host Header](#rewriting-the-host-header)
|
||||||
|
* [Set Headers In HTTP Request](#set-headers-in-http-request)
|
||||||
* [Get Real IP](#get-real-ip)
|
* [Get Real IP](#get-real-ip)
|
||||||
* [Password protecting your web service](#password-protecting-your-web-service)
|
* [Password protecting your web service](#password-protecting-your-web-service)
|
||||||
* [Custom subdomain names](#custom-subdomain-names)
|
* [Custom subdomain names](#custom-subdomain-names)
|
||||||
@ -485,7 +486,7 @@ This feature is fit for a large number of short connections.
|
|||||||
|
|
||||||
### Rewriting the Host Header
|
### Rewriting the Host Header
|
||||||
|
|
||||||
When forwarding to a local port, frp does not modify the tunneled HTTP requests at all, they are copied to your server byte-for-byte as they are received. Some application servers use the Host header for determining which development site to display. For this reason, frp can rewrite your requests with a modified Host header. Use the `host_header_rewrite` switch to rewrite incoming HTTP requests.
|
When forwarding to a local port, frp does not modify the tunneled HTTP requests at all, they are copied to your server byte-for-byte as they are received. Some application servers use the Host header for determining which development site to display. For this reason, frp can rewrite your requests with a modified host header. Use the `host_header_rewrite` switch to rewrite incoming HTTP requests.
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# frpc.ini
|
# frpc.ini
|
||||||
@ -496,7 +497,24 @@ custom_domains = test.yourdomain.com
|
|||||||
host_header_rewrite = dev.yourdomain.com
|
host_header_rewrite = dev.yourdomain.com
|
||||||
```
|
```
|
||||||
|
|
||||||
If `host_header_rewrite` is specified, the Host header will be rewritten to match the hostname portion of the forwarding address.
|
If `host_header_rewrite` is specified, the host header will be rewritten to match the hostname portion of the forwarding address.
|
||||||
|
|
||||||
|
### Set Headers In HTTP Request
|
||||||
|
|
||||||
|
You can set headers for proxy which type is `http`.
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# frpc.ini
|
||||||
|
[web]
|
||||||
|
type = http
|
||||||
|
local_port = 80
|
||||||
|
custom_domains = test.yourdomain.com
|
||||||
|
host_header_rewrite = dev.yourdomain.com
|
||||||
|
header_X-From-Where = frp
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that params which have prefix `header_` will be added to http request headers.
|
||||||
|
In this example, it will set header `X-From-Where: frp` to http request.
|
||||||
|
|
||||||
### Get Real IP
|
### Get Real IP
|
||||||
|
|
||||||
|
17
README_zh.md
17
README_zh.md
@ -34,6 +34,7 @@ frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp
|
|||||||
* [底层通信可选 kcp 协议](#底层通信可选-kcp-协议)
|
* [底层通信可选 kcp 协议](#底层通信可选-kcp-协议)
|
||||||
* [连接池](#连接池)
|
* [连接池](#连接池)
|
||||||
* [修改 Host Header](#修改-host-header)
|
* [修改 Host Header](#修改-host-header)
|
||||||
|
* [设置 http 请求的 header](#设置-http-请求的-header)
|
||||||
* [获取用户真实 IP](#获取用户真实-ip)
|
* [获取用户真实 IP](#获取用户真实-ip)
|
||||||
* [通过密码保护你的 web 服务](#通过密码保护你的-web-服务)
|
* [通过密码保护你的 web 服务](#通过密码保护你的-web-服务)
|
||||||
* [自定义二级域名](#自定义二级域名)
|
* [自定义二级域名](#自定义二级域名)
|
||||||
@ -525,6 +526,22 @@ host_header_rewrite = dev.yourdomain.com
|
|||||||
|
|
||||||
原来 http 请求中的 host 字段 `test.yourdomain.com` 转发到后端服务时会被替换为 `dev.yourdomain.com`。
|
原来 http 请求中的 host 字段 `test.yourdomain.com` 转发到后端服务时会被替换为 `dev.yourdomain.com`。
|
||||||
|
|
||||||
|
### 设置 http 请求的 header
|
||||||
|
|
||||||
|
对于 `type = http` 的代理,可以设置在转发中动态添加的 header 参数。
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# frpc.ini
|
||||||
|
[web]
|
||||||
|
type = http
|
||||||
|
local_port = 80
|
||||||
|
custom_domains = test.yourdomain.com
|
||||||
|
host_header_rewrite = dev.yourdomain.com
|
||||||
|
header_X-From-Where = frp
|
||||||
|
```
|
||||||
|
|
||||||
|
对于参数配置中所有以 `header_` 开头的参数(支持同时配置多个),都会被添加到 http 请求的 header 中,根据如上的配置,会在请求的 header 中加上 `X-From-Where: frp`。
|
||||||
|
|
||||||
### 获取用户真实 IP
|
### 获取用户真实 IP
|
||||||
|
|
||||||
目前只有 **http** 类型的代理支持这一功能,可以通过用户请求的 header 中的 `X-Forwarded-For` 和 `X-Real-IP` 来获取用户真实 IP。
|
目前只有 **http** 类型的代理支持这一功能,可以通过用户请求的 header 中的 `X-Forwarded-For` 和 `X-Real-IP` 来获取用户真实 IP。
|
||||||
|
@ -56,10 +56,10 @@ dns_server = 8.8.8.8
|
|||||||
# heartbeat_interval = 30
|
# heartbeat_interval = 30
|
||||||
# heartbeat_timeout = 90
|
# heartbeat_timeout = 90
|
||||||
|
|
||||||
# ssh is the proxy name same as server's configuration
|
# 'ssh' is the unique proxy name
|
||||||
# if user in [common] section is not empty, it will be changed to {user}.{proxy} such as your_name.ssh
|
# if user in [common] section is not empty, it will be changed to {user}.{proxy} such as 'your_name.ssh'
|
||||||
[ssh]
|
[ssh]
|
||||||
# tcp | udp | http | https, default is tcp
|
# tcp | udp | http | https | stcp | xtcp, default is tcp
|
||||||
type = tcp
|
type = tcp
|
||||||
local_ip = 127.0.0.1
|
local_ip = 127.0.0.1
|
||||||
local_port = 22
|
local_port = 22
|
||||||
@ -120,6 +120,8 @@ custom_domains = web02.yourdomain.com
|
|||||||
# locations is only available for http type
|
# locations is only available for http type
|
||||||
locations = /,/pic
|
locations = /,/pic
|
||||||
host_header_rewrite = example.com
|
host_header_rewrite = example.com
|
||||||
|
# params with prefix "header_" will be used to update http request headers
|
||||||
|
header_X-From-Where = frp
|
||||||
|
|
||||||
[web02]
|
[web02]
|
||||||
type = https
|
type = https
|
||||||
@ -136,7 +138,7 @@ remote_port = 6003
|
|||||||
# if plugin is defined, local_ip and local_port is useless
|
# if plugin is defined, local_ip and local_port is useless
|
||||||
# plugin will handle connections got from frps
|
# plugin will handle connections got from frps
|
||||||
plugin = unix_domain_socket
|
plugin = unix_domain_socket
|
||||||
# params set with prefix "plugin_" that plugin needed
|
# params with prefix "plugin_" that plugin needed
|
||||||
plugin_unix_path = /var/run/docker.sock
|
plugin_unix_path = /var/run/docker.sock
|
||||||
|
|
||||||
[plugin_http_proxy]
|
[plugin_http_proxy]
|
||||||
|
@ -430,9 +430,10 @@ type HttpProxyConf struct {
|
|||||||
LocalSvrConf
|
LocalSvrConf
|
||||||
|
|
||||||
Locations []string `json:"locations"`
|
Locations []string `json:"locations"`
|
||||||
HostHeaderRewrite string `json:"host_header_rewrite"`
|
|
||||||
HttpUser string `json:"http_user"`
|
HttpUser string `json:"http_user"`
|
||||||
HttpPwd string `json:"http_pwd"`
|
HttpPwd string `json:"http_pwd"`
|
||||||
|
HostHeaderRewrite string `json:"host_header_rewrite"`
|
||||||
|
Headers map[string]string `json:"headers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpProxyConf) Compare(cmp ProxyConf) bool {
|
func (cfg *HttpProxyConf) Compare(cmp ProxyConf) bool {
|
||||||
@ -447,9 +448,20 @@ func (cfg *HttpProxyConf) Compare(cmp ProxyConf) bool {
|
|||||||
strings.Join(cfg.Locations, " ") != strings.Join(cmpConf.Locations, " ") ||
|
strings.Join(cfg.Locations, " ") != strings.Join(cmpConf.Locations, " ") ||
|
||||||
cfg.HostHeaderRewrite != cmpConf.HostHeaderRewrite ||
|
cfg.HostHeaderRewrite != cmpConf.HostHeaderRewrite ||
|
||||||
cfg.HttpUser != cmpConf.HttpUser ||
|
cfg.HttpUser != cmpConf.HttpUser ||
|
||||||
cfg.HttpPwd != cmpConf.HttpPwd {
|
cfg.HttpPwd != cmpConf.HttpPwd ||
|
||||||
|
len(cfg.Headers) != len(cmpConf.Headers) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for k, v := range cfg.Headers {
|
||||||
|
if v2, ok := cmpConf.Headers[k]; !ok {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
if v != v2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,6 +473,7 @@ func (cfg *HttpProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) {
|
|||||||
cfg.HostHeaderRewrite = pMsg.HostHeaderRewrite
|
cfg.HostHeaderRewrite = pMsg.HostHeaderRewrite
|
||||||
cfg.HttpUser = pMsg.HttpUser
|
cfg.HttpUser = pMsg.HttpUser
|
||||||
cfg.HttpPwd = pMsg.HttpPwd
|
cfg.HttpPwd = pMsg.HttpPwd
|
||||||
|
cfg.Headers = pMsg.Headers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpProxyConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
func (cfg *HttpProxyConf) UnmarshalFromIni(prefix string, name string, section ini.Section) (err error) {
|
||||||
@ -487,6 +500,13 @@ func (cfg *HttpProxyConf) UnmarshalFromIni(prefix string, name string, section i
|
|||||||
cfg.HostHeaderRewrite = section["host_header_rewrite"]
|
cfg.HostHeaderRewrite = section["host_header_rewrite"]
|
||||||
cfg.HttpUser = section["http_user"]
|
cfg.HttpUser = section["http_user"]
|
||||||
cfg.HttpPwd = section["http_pwd"]
|
cfg.HttpPwd = section["http_pwd"]
|
||||||
|
cfg.Headers = make(map[string]string)
|
||||||
|
|
||||||
|
for k, v := range section {
|
||||||
|
if strings.HasPrefix(k, "header_") {
|
||||||
|
cfg.Headers[strings.TrimPrefix(k, "header_")] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,6 +518,7 @@ func (cfg *HttpProxyConf) MarshalToMsg(pMsg *msg.NewProxy) {
|
|||||||
pMsg.HostHeaderRewrite = cfg.HostHeaderRewrite
|
pMsg.HostHeaderRewrite = cfg.HostHeaderRewrite
|
||||||
pMsg.HttpUser = cfg.HttpUser
|
pMsg.HttpUser = cfg.HttpUser
|
||||||
pMsg.HttpPwd = cfg.HttpPwd
|
pMsg.HttpPwd = cfg.HttpPwd
|
||||||
|
pMsg.Headers = cfg.Headers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpProxyConf) CheckForCli() (err error) {
|
func (cfg *HttpProxyConf) CheckForCli() (err error) {
|
||||||
|
@ -94,9 +94,10 @@ type NewProxy struct {
|
|||||||
CustomDomains []string `json:"custom_domains"`
|
CustomDomains []string `json:"custom_domains"`
|
||||||
SubDomain string `json:"subdomain"`
|
SubDomain string `json:"subdomain"`
|
||||||
Locations []string `json:"locations"`
|
Locations []string `json:"locations"`
|
||||||
HostHeaderRewrite string `json:"host_header_rewrite"`
|
|
||||||
HttpUser string `json:"http_user"`
|
HttpUser string `json:"http_user"`
|
||||||
HttpPwd string `json:"http_pwd"`
|
HttpPwd string `json:"http_pwd"`
|
||||||
|
HostHeaderRewrite string `json:"host_header_rewrite"`
|
||||||
|
Headers map[string]string `json:"headers"`
|
||||||
|
|
||||||
// stcp
|
// stcp
|
||||||
Sk string `json:"sk"`
|
Sk string `json:"sk"`
|
||||||
|
@ -225,6 +225,7 @@ type HttpProxy struct {
|
|||||||
func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
||||||
routeConfig := vhost.VhostRouteConfig{
|
routeConfig := vhost.VhostRouteConfig{
|
||||||
RewriteHost: pxy.cfg.HostHeaderRewrite,
|
RewriteHost: pxy.cfg.HostHeaderRewrite,
|
||||||
|
Headers: pxy.cfg.Headers,
|
||||||
Username: pxy.cfg.HttpUser,
|
Username: pxy.cfg.HttpUser,
|
||||||
Password: pxy.cfg.HttpPwd,
|
Password: pxy.cfg.HttpPwd,
|
||||||
CreateConnFn: pxy.GetRealConn,
|
CreateConnFn: pxy.GetRealConn,
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version string = "0.19.1"
|
var version string = "0.20.0"
|
||||||
|
|
||||||
func Full() string {
|
func Full() string {
|
||||||
return version
|
return version
|
||||||
|
@ -63,12 +63,17 @@ func NewHttpReverseProxy() *HttpReverseProxy {
|
|||||||
Director: func(req *http.Request) {
|
Director: func(req *http.Request) {
|
||||||
req.URL.Scheme = "http"
|
req.URL.Scheme = "http"
|
||||||
url := req.Context().Value("url").(string)
|
url := req.Context().Value("url").(string)
|
||||||
host := getHostFromAddr(req.Context().Value("host").(string))
|
oldHost := getHostFromAddr(req.Context().Value("host").(string))
|
||||||
host = rp.GetRealHost(host, url)
|
host := rp.GetRealHost(oldHost, url)
|
||||||
if host != "" {
|
if host != "" {
|
||||||
req.Host = host
|
req.Host = host
|
||||||
}
|
}
|
||||||
req.URL.Host = req.Host
|
req.URL.Host = req.Host
|
||||||
|
|
||||||
|
headers := rp.GetHeaders(oldHost, url)
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
ResponseHeaderTimeout: responseHeaderTimeout,
|
ResponseHeaderTimeout: responseHeaderTimeout,
|
||||||
@ -117,6 +122,14 @@ func (rp *HttpReverseProxy) GetRealHost(domain string, location string) (host st
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rp *HttpReverseProxy) GetHeaders(domain string, location string) (headers map[string]string) {
|
||||||
|
vr, ok := rp.getVhost(domain, location)
|
||||||
|
if ok {
|
||||||
|
headers = vr.payload.(*VhostRouteConfig).Headers
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (rp *HttpReverseProxy) CreateConnection(domain string, location string) (net.Conn, error) {
|
func (rp *HttpReverseProxy) CreateConnection(domain string, location string) (net.Conn, error) {
|
||||||
vr, ok := rp.getVhost(domain, location)
|
vr, ok := rp.getVhost(domain, location)
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -59,6 +59,7 @@ type VhostRouteConfig struct {
|
|||||||
RewriteHost string
|
RewriteHost string
|
||||||
Username string
|
Username string
|
||||||
Password string
|
Password string
|
||||||
|
Headers map[string]string
|
||||||
|
|
||||||
CreateConnFn CreateConnFunc
|
CreateConnFn CreateConnFunc
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user