Index: include/types/backend.h =================================================================== --- include/types/backend.h (révision 2) +++ include/types/backend.h (révision 3) @@ -61,6 +61,7 @@ #define PR_O_BALANCE (PR_O_BALANCE_RR | PR_O_BALANCE_SH | PR_O_BALANCE_UH) #define PR_O_SMTP_CHK 0x20000000 /* use SMTP EHLO check for server health - pvandijk@vision6.com.au */ #define PR_O_TCP_LINGER 0x40000000 /* linger handling client connection */ +#define PR_O_HTTP_PROXY 0x80000000 /* Enable session to use HTTP proxy operations */ #endif /* _TYPES_BACKEND_H */ Index: src/backend.c =================================================================== --- src/backend.c (révision 2) +++ src/backend.c (révision 3) @@ -163,7 +163,13 @@ return SRV_STATUS_INTERNAL; if (!(s->flags & SN_ASSIGNED)) { - if (s->be->options & PR_O_BALANCE) { + if (s->be->options & PR_O_HTTP_PROXY) { + if (s->srv_addr.sin_addr.s_addr == 0) + return SRV_STATUS_NOSRV; + s->flags |= SN_ASSIGNED; + return SRV_STATUS_OK; + } + else if (s->be->options & PR_O_BALANCE) { if (s->flags & SN_DIRECT) { s->flags |= SN_ASSIGNED; return SRV_STATUS_OK; @@ -228,7 +234,15 @@ fprintf(stderr,"assign_server_address : s=%p\n",s); #endif - if ((s->flags & SN_DIRECT) || (s->be->options & PR_O_BALANCE)) { + /* + * If HTTP PROXY option is set, then server is already assigned + * during incoming client request parsing. + */ + if (s->be->options & PR_O_HTTP_PROXY) { + s->flags |= SN_ADDR_SET; + return SRV_STATUS_OK; + } + else if ((s->flags & SN_DIRECT) || (s->be->options & PR_O_BALANCE)) { /* A server is necessarily known for this session */ if (!(s->flags & SN_ASSIGNED)) return SRV_STATUS_INTERNAL; Index: src/cfgparse.c =================================================================== --- src/cfgparse.c (révision 2) +++ src/cfgparse.c (révision 3) @@ -93,6 +93,7 @@ { "keepalive", PR_O_KEEPALIVE, PR_CAP_NONE, 0 }, { "httpclose", PR_O_HTTP_CLOSE, PR_CAP_FE | PR_CAP_BE, 0 }, { "linger", PR_O_TCP_LINGER, PR_CAP_FE | PR_CAP_BE, 0 }, + { "proxy", PR_O_HTTP_PROXY, PR_CAP_FE | PR_CAP_BE, 0 }, { "logasap", PR_O_LOGASAP, PR_CAP_FE, 0 }, { "abortonclose", PR_O_ABRT_CLOSE, PR_CAP_BE, 0 }, { "checkcache", PR_O_CHK_CACHE, PR_CAP_BE, 0 }, Index: src/proto_http.c =================================================================== --- src/proto_http.c (révision 2) +++ src/proto_http.c (révision 3) @@ -368,6 +368,114 @@ static void http_sess_log(struct session *s); /* + * Parse IP address in url + */ +static int get_ip_address_from_uri(const char *addr, const char *end, unsigned long *dst) +{ + static char digits[] = "0123456789"; + int saw_digit, octets, ch; + u_char tmp[4], *tp; + const char *cp = addr; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + + while (addr != end && (ch = *addr++) != '/' && ch != ':') { + const char *pch; + if ((pch = strchr(digits, ch)) != NULL) { + u_int new = *tp * 10 + (pch - digits); + if (new > 255) + return 0; + *tp = new; + if (!saw_digit) { + if (++octets > 4) + return 0; + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return 0; + *++tp = 0; + saw_digit = 0; + } else + return 0; + } + + if (octets < 4) + return 0; + + memcpy(dst, tmp, 4); + return addr-cp-1; +} +static int get_port_from_uri(const char *addr, const char *end, unsigned short *dst) +{ + const char *cp = addr; + unsigned short tmp = 0; + int ch; + + while (addr != end && (ch = *addr++) != '/') + tmp = 10*tmp + (ch - 0x30); + + *dst = htons(tmp); + return addr-cp-1; +} + +/* + * Resolv destination server from URI when using PR_O_HTTP_PROXY + */ +static int get_srv_from_uri(struct sockaddr_in *addr, char *buffer, int len) +{ + char *cp = buffer; + char *curr; + int url_code = 0; + int ret; + + /* Cleanup the room */ + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = 0; + addr->sin_port = 0; + + /* + * http:// sanity check. + * Firstly, we try to find :// pattern. + */ + for (curr = buffer; url_code != 0x98 && curr != buffer+len; curr++) { + if (*curr == ':' || *curr == '/') + url_code += (int) *curr; + } + + /* + * Secondly, if :// pattern is found, verify parsed stuff + * before pattern is matching our http pattern. + * If so parse ip address and port in uri. + * + * WARNING: Current code doesn't support dynamic async dns resolver. + */ + if (url_code == 0x98) { /* We got a :// */ + if (curr-cp == 7 && /* Only support HTTP proxy */ + ((*cp == 'h' || *cp == 'H') && + (*(cp+1) == 't' || *(cp+1) == 'T') && + (*(cp+2) == 't' || *(cp+2) == 'T') && + (*(cp+3) == 'p' || *(cp+3) == 'P'))) { + ret = get_ip_address_from_uri(curr, buffer+len, (unsigned long *) &addr->sin_addr.s_addr); + if (!ret) + return -1; + curr += ret; + if (*curr == ':') { + ret = get_port_from_uri(++curr, buffer+len, &addr->sin_port); + if (!ret) + return -1; + } else + addr->sin_port = htons(80); + } + return 0; + } + + return -1; +} + +/* * Adds a header and its CRLF at the tail of buffer , just before the last * CRLF. Text length is measured first, so it cannot be NULL. * The header is also automatically added to the index , and the end @@ -1955,9 +2063,14 @@ * may have separate values for ->fe, ->be. */ + /* + * If HTTP PROXY is set we simply get remote server address + * parsing incoming request. + */ + if (t->be->options & PR_O_HTTP_PROXY) { + get_srv_from_uri(&t->srv_addr, req->data+msg->sl.rq.u, msg->sl.rq.u_l); + } - - /* * 7: the appsession cookie was looked up very early in 1.2, * so let's do the same now.