diff options
author | olgeni <olgeni@FreeBSD.org> | 2015-02-21 07:37:01 +0800 |
---|---|---|
committer | olgeni <olgeni@FreeBSD.org> | 2015-02-21 07:37:01 +0800 |
commit | 733f2dec28151c415dfce061ac6c97d0e3eb110e (patch) | |
tree | 557470ce31c461322e4611a8374e81ec7f722e6c /lang | |
parent | 8b8bbec19a5a379a30a789f351343d4623855aaa (diff) | |
download | freebsd-ports-gnome-733f2dec28151c415dfce061ac6c97d0e3eb110e.tar.gz freebsd-ports-gnome-733f2dec28151c415dfce061ac6c97d0e3eb110e.tar.zst freebsd-ports-gnome-733f2dec28151c415dfce061ac6c97d0e3eb110e.zip |
Upgrade to version 17.4.1.
Diffstat (limited to 'lang')
-rw-r--r-- | lang/erlang-runtime17/Makefile | 14 | ||||
-rw-r--r-- | lang/erlang-runtime17/files/patch-otp-17.4.1 | 1358 |
2 files changed, 1369 insertions, 3 deletions
diff --git a/lang/erlang-runtime17/Makefile b/lang/erlang-runtime17/Makefile index ce2038432e04..0adf47b813e6 100644 --- a/lang/erlang-runtime17/Makefile +++ b/lang/erlang-runtime17/Makefile @@ -2,8 +2,7 @@ # $FreeBSD$ PORTNAME= erlang -PORTVERSION= 17.4 -PORTREVISION= 2 +PORTVERSION= 17.4.1 CATEGORIES= lang parallel java MASTER_SITES= http://www.erlang.org/download/:erlangorg \ http://erlang.stacken.kth.se/download/:erlangorg \ @@ -42,7 +41,7 @@ DTRACE_DESC= Enable DTrace support OPTIONS_DEFAULT=KQUEUE OPENSSL SCTP SMP THREADS -ERL_RELEASE= ${PORTVERSION} +ERL_RELEASE= 17.4 USES= gmake perl5 USE_AUTOTOOLS= autoconf:env @@ -187,6 +186,15 @@ post-install: .if ${PORT_OPTIONS:MDOCS} ${TAR} --unlink -xzpf ${DISTDIR}/${DIST_SUBDIR}/${ERLANG_DOCS} \ -C ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB} + + ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.4/* \ + ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.5 + ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/inets-5.10.4 + + ${MV} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/erts-6.3/* \ + ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/erts-6.3.1 + ${RMDIR} ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/erts-6.3 + ${INSTALL_DATA} ${WRKSRC}/lib/dialyzer/doc/*.txt \ ${STAGEDIR}${PREFIX}/lib/${ERLANG_LIB}/lib/dialyzer-*/doc/ .endif diff --git a/lang/erlang-runtime17/files/patch-otp-17.4.1 b/lang/erlang-runtime17/files/patch-otp-17.4.1 new file mode 100644 index 000000000000..a6e71eefcdbd --- /dev/null +++ b/lang/erlang-runtime17/files/patch-otp-17.4.1 @@ -0,0 +1,1358 @@ +diff --git OTP_VERSION OTP_VERSION +index 5f9cbaa..ae704d6 100644 +--- OTP_VERSION ++++ OTP_VERSION +@@ -1 +1 @@ +-17.4 ++17.4.1 +diff --git erts/doc/src/notes.xml erts/doc/src/notes.xml +index c896ee0..af0d4d7 100644 +--- erts/doc/src/notes.xml ++++ erts/doc/src/notes.xml +@@ -30,6 +30,65 @@ + </header> + <p>This document describes the changes made to the ERTS application.</p> + ++<section><title>Erts 6.3.1</title> ++ ++ <section><title>Fixed Bugs and Malfunctions</title> ++ <list> ++ <item> ++ <p> ++ Fix getifaddrs realloc pointer error</p> ++ <p> ++ When a buffer was exhausted and subsequently reallocated, ++ we could get an unsafe pointer pointing to faulty memory.</p> ++ <p> ++ For this to occur we would need to have a large number of ++ interfaces and a reallocation of memory to a lower ++ addresses.</p> ++ <p> ++ The symptom would be garbage returned from ++ erlang:port_control(Port, 25, []) ++ (prim_inet:getifaddrs(Port) resulting in a badarg) or a ++ segmentation fault.</p> ++ <p> ++ Own Id: OTP-12445</p> ++ </item> ++ <item> ++ <p> ++ Don't close all file descriptors twice in child_setup</p> ++ <p> ++ The commit c2b4eab25c907f453a394d382c04cd04e6c06b49 ++ introduced an error in which child_setup erroneously ++ tried to close all file descriptors twice.</p> ++ <p> ++ Use closefrom() if available when closing all file ++ descriptors.</p> ++ <p> ++ The function closefrom() was only used in the vfork() ++ case before but is now also used in the fork() case if ++ available.</p> ++ <p> ++ Own Id: OTP-12446</p> ++ </item> ++ <item> ++ <p> ++ During a crashdump all file descriptors are closed to ++ ensure the closing of the epmd port and to reserve a file ++ descriptor for the crashdump file.</p> ++ <p> ++ If a driver (third party library) cannot handle closing ++ of sockets this could result in a segmentation fault in ++ which case a crashdump would not be produced. This is now ++ fixed by only closing inets sockets via an emergency ++ close callback to the driver and thus closing the epmd ++ socket.</p> ++ <p> ++ Own Id: OTP-12447</p> ++ </item> ++ </list> ++ </section> ++ ++</section> ++ + <section><title>Erts 6.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> +diff --git erts/emulator/beam/erl_driver.h erts/emulator/beam/erl_driver.h +index f9938fc..e498ac7 100644 +--- erts/emulator/beam/erl_driver.h ++++ erts/emulator/beam/erl_driver.h +@@ -133,7 +133,7 @@ typedef struct { + + #define ERL_DRV_EXTENDED_MARKER (0xfeeeeeed) + #define ERL_DRV_EXTENDED_MAJOR_VERSION 3 +-#define ERL_DRV_EXTENDED_MINOR_VERSION 1 ++#define ERL_DRV_EXTENDED_MINOR_VERSION 2 + + /* + * The emulator will refuse to load a driver with a major version +@@ -361,6 +361,9 @@ typedef struct erl_drv_entry { + /* Called on behalf of driver_select when + it is safe to release 'event'. A typical + unix driver would call close(event) */ ++ void (*emergency_close)(ErlDrvData drv_data); ++ /* called when the port is closed abruptly. ++ specifically when erl_crash_dump is called. */ + /* When adding entries here, dont forget to pad in obsolete/driver.h */ + } ErlDrvEntry; + +diff --git erts/emulator/beam/global.h erts/emulator/beam/global.h +index 891046a..32a2dc4 100644 +--- erts/emulator/beam/global.h ++++ erts/emulator/beam/global.h +@@ -160,6 +160,7 @@ struct erts_driver_t_ { + void (*ready_async)(ErlDrvData drv_data, ErlDrvThreadData thread_data); /* Might be NULL */ + void (*process_exit)(ErlDrvData drv_data, ErlDrvMonitor *monitor); + void (*stop_select)(ErlDrvEvent event, void*); /* Might be NULL */ ++ void (*emergency_close)(ErlDrvData drv_data); /* Might be NULL */ + }; + + extern erts_driver_t *driver_list; +@@ -852,6 +853,7 @@ Uint erts_port_ioq_size(Port *pp); + void erts_stale_drv_select(Eterm, ErlDrvPort, ErlDrvEvent, int, int); + + Port *erts_get_heart_port(void); ++void erts_emergency_close_ports(void); + + #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_COUNT) + void erts_lcnt_enable_io_lock_count(int enable); +diff --git erts/emulator/beam/io.c erts/emulator/beam/io.c +index 9ae973e..012a7d1 100644 +--- erts/emulator/beam/io.c ++++ erts/emulator/beam/io.c +@@ -7349,6 +7349,8 @@ no_stop_select_callback(ErlDrvEvent event, void* private) + erts_send_error_to_logger_nogl(dsbufp); + } + ++#define IS_DRIVER_VERSION_GE(DE,MAJOR,MINOR) \ ++ ((DE)->major_version >= (MAJOR) && (DE)->minor_version >= (MINOR)) + + static int + init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle) +@@ -7396,6 +7398,7 @@ init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle) + drv->timeout = de->timeout ? de->timeout : no_timeout_callback; + drv->ready_async = de->ready_async; + drv->process_exit = de->process_exit; ++ drv->emergency_close = IS_DRIVER_VERSION_GE(de,3,2) ? de->emergency_close : NULL; + if (de->stop_select) + drv->stop_select = de->stop_select; + else +@@ -7414,6 +7417,8 @@ init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle) + } + } + ++#undef IS_DRIVER_VERSION_GE ++ + void + erts_destroy_driver(erts_driver_t *drv) + { +@@ -7557,7 +7562,7 @@ Port *erts_get_heart_port(void) + if (!port) + continue; + /* only examine undead or alive ports */ +- if (erts_atomic32_read_nob(&port->state) & ERTS_PORT_SFLGS_DEAD) ++ if (erts_atomic32_read_nob(&port->state) & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) + continue; + /* immediate atom compare */ + reg = port->common.u.alive.reg; +@@ -7568,3 +7573,23 @@ Port *erts_get_heart_port(void) + + return NULL; + } ++ ++void erts_emergency_close_ports(void) ++{ ++ int ix, max = erts_ptab_max(&erts_port); ++ ++ for (ix = 0; ix < max; ix++) { ++ Port *port = erts_pix2port(ix); ++ ++ if (!port) ++ continue; ++ /* only examine undead or alive ports */ ++ if (erts_atomic32_read_nob(&port->state) & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) ++ continue; ++ ++ /* emergency close socket */ ++ if (port->drv_ptr->emergency_close) { ++ port->drv_ptr->emergency_close((ErlDrvData) port->drv_data); ++ } ++ } ++} +diff --git erts/emulator/drivers/common/inet_drv.c erts/emulator/drivers/common/inet_drv.c +index db8a251..04721d2 100644 +--- erts/emulator/drivers/common/inet_drv.c ++++ erts/emulator/drivers/common/inet_drv.c +@@ -268,14 +268,13 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD); + #define sock_htonl(x) htonl((x)) + #define sock_send(s,buf,len,flag) send((s),(buf),(len),(flag)) + #define sock_sendv(s, vec, size, np, flag) \ +- WSASend((s),(WSABUF*)(vec),\ +- (size),(np),(flag),NULL,NULL) ++ WSASend((s),(WSABUF*)(vec),(size),(np),(flag),NULL,NULL) + #define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) + + #define sock_recvfrom(s,buf,blen,flag,addr,alen) \ +- recvfrom((s),(buf),(blen),(flag),(addr),(alen)) ++ recvfrom((s),(buf),(blen),(flag),(addr),(alen)) + #define sock_sendto(s,buf,blen,flag,addr,alen) \ +- sendto((s),(buf),(blen),(flag),(addr),(alen)) ++ sendto((s),(buf),(blen),(flag),(addr),(alen)) + #define sock_hostname(buf, len) gethostname((buf), (len)) + + #define sock_getservbyname(name,proto) getservbyname((name),(proto)) +@@ -360,9 +359,9 @@ static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int + #define sock_accept(s, addr, len) accept((s), (addr), (len)) + #define sock_send(s,buf,len,flag) inet_send((s),(buf),(len),(flag)) + #define sock_sendto(s,buf,blen,flag,addr,alen) \ +- sendto((s),(buf),(blen),(flag),(addr),(alen)) ++ sendto((s),(buf),(blen),(flag),(addr),(alen)) + #define sock_sendv(s, vec, size, np, flag) \ +- (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) ++ (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) + #define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) + + #define sock_open(af, type, proto) socket((af), (type), (proto)) +@@ -1178,6 +1177,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int, + static void tcp_inet_timeout(ErlDrvData); + static void tcp_inet_process_exit(ErlDrvData, ErlDrvMonitor *); + static void inet_stop_select(ErlDrvEvent, void*); ++static void inet_emergency_close(ErlDrvData); + #ifdef __WIN32__ + static void tcp_inet_event(ErlDrvData, ErlDrvEvent); + static void find_dynamic_functions(void); +@@ -1288,7 +1288,8 @@ static struct erl_drv_entry tcp_inet_driver_entry = + ERL_DRV_FLAG_USE_PORT_LOCKING|ERL_DRV_FLAG_SOFT_BUSY, + NULL, + tcp_inet_process_exit, +- inet_stop_select ++ inet_stop_select, ++ inet_emergency_close + }; + + +@@ -1341,7 +1342,8 @@ static struct erl_drv_entry udp_inet_driver_entry = + ERL_DRV_FLAG_USE_PORT_LOCKING, + NULL, + NULL, +- inet_stop_select ++ inet_stop_select, ++ inet_emergency_close + }; + #endif + +@@ -1375,7 +1377,8 @@ static struct erl_drv_entry sctp_inet_driver_entry = + ERL_DRV_FLAG_USE_PORT_LOCKING, + NULL, + NULL, /* process_exit */ +- inet_stop_select ++ inet_stop_select, ++ inet_emergency_close + }; + #endif + +@@ -1421,7 +1424,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event); + static int packet_inet_output(udp_descriptor* udesc, HANDLE event); + #endif + +-/* convert descriptor poiner to inet_descriptor pointer */ ++/* convert descriptor pointer to inet_descriptor pointer */ + #define INETP(d) (&(d)->inet) + + #ifdef __OSE__ +@@ -4721,6 +4724,36 @@ static char* sockaddr_to_buf(struct sockaddr* addr, char* ptr, char* end) + return NULL; + } + ++/* sockaddr_bufsz_need ++ * Returns the number of bytes needed to store the information ++ * through sockaddr_to_buf ++ */ ++ ++static size_t sockaddr_bufsz_need(struct sockaddr* addr) ++{ ++ if (addr->sa_family == AF_INET || addr->sa_family == 0) { ++ return 1 + sizeof(struct in_addr); ++ } ++#if defined(HAVE_IN6) && defined(AF_INET6) ++ else if (addr->sa_family == AF_INET6) { ++ return 1 + sizeof(struct in6_addr); ++ } ++#endif ++#if defined(AF_LINK) ++ if (addr->sa_family == AF_LINK) { ++ struct sockaddr_dl *sdl_p = (struct sockaddr_dl*) addr; ++ return 2 + sdl_p->sdl_alen; ++ } ++#endif ++#if defined(AF_PACKET) && defined(HAVE_NETPACKET_PACKET_H) ++ else if(addr->sa_family == AF_PACKET) { ++ struct sockaddr_ll *sll_p = (struct sockaddr_ll*) addr; ++ return 2 + sll_p->sll_halen; ++ } ++#endif ++ return 0; ++} ++ + static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr) + { + buf_check(ptr,end,1); +@@ -5799,6 +5832,11 @@ done: + } + + #elif defined(HAVE_GETIFADDRS) ++#ifdef DEBUG ++#define GETIFADDRS_BUFSZ (1) ++#else ++#define GETIFADDRS_BUFSZ (512) ++#endif + + static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, + char **rbuf_pp, ErlDrvSizeT rsize) +@@ -5809,15 +5847,15 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, + char *buf_p; + char *buf_alloc_p; + +- buf_size = 512; +- buf_alloc_p = ALLOC(buf_size); ++ buf_size = GETIFADDRS_BUFSZ; ++ buf_alloc_p = ALLOC(GETIFADDRS_BUFSZ); + buf_p = buf_alloc_p; + # define BUF_ENSURE(Size) \ + do { \ + int NEED_, GOT_ = buf_p - buf_alloc_p; \ + NEED_ = GOT_ + (Size); \ + if (NEED_ > buf_size) { \ +- buf_size = NEED_ + 512; \ ++ buf_size = NEED_ + GETIFADDRS_BUFSZ; \ + buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \ + buf_p = buf_alloc_p + GOT_; \ + } \ +@@ -5830,7 +5868,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, + while (! (P_ = sockaddr_to_buf((sa), buf_p, \ + buf_alloc_p+buf_size))) { \ + int GOT_ = buf_p - buf_alloc_p; \ +- buf_size += 512; \ ++ buf_size += GETIFADDRS_BUFSZ; \ + buf_alloc_p = REALLOC(buf_alloc_p, buf_size); \ + buf_p = buf_alloc_p + GOT_; \ + } \ +@@ -5887,10 +5925,11 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, + || ifa_p->ifa_addr->sa_family == AF_PACKET + #endif + ) { +- char *bp = buf_p; +- BUF_ENSURE(1); +- SOCKADDR_TO_BUF(INET_IFOPT_HWADDR, ifa_p->ifa_addr); +- if (buf_p - bp < 4) buf_p = bp; /* Empty hwaddr */ ++ size_t need = sockaddr_bufsz_need(ifa_p->ifa_addr); ++ if (need > 3) { ++ BUF_ENSURE(1 + need); ++ SOCKADDR_TO_BUF(INET_IFOPT_HWADDR, ifa_p->ifa_addr); ++ } + } + #endif + } +@@ -5905,6 +5944,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, + return buf_size; + # undef BUF_ENSURE + } ++#undef GETIFADDRS_BUFSZ + + #else + +@@ -8204,6 +8244,19 @@ static void inet_stop(inet_descriptor* desc) + FREE(desc); + } + ++static void inet_emergency_close(ErlDrvData data) ++{ ++ /* valid for any (UDP, TCP or SCTP) descriptor */ ++ tcp_descriptor* tcp_desc = (tcp_descriptor*)data; ++ inet_descriptor* desc = INETP(tcp_desc); ++ DEBUGF(("inet_emergency_close(%ld) {s=%d\r\n", ++ (long)desc->port, desc->s)); ++ if (desc->s != INVALID_SOCKET) { ++ sock_close(desc->s); ++ } ++} ++ ++ + static void set_default_msgq_limits(ErlDrvPort port) + { + ErlDrvSizeT q_high = INET_HIGH_MSGQ_WATERMARK; +diff --git erts/emulator/sys/unix/erl_child_setup.c erts/emulator/sys/unix/erl_child_setup.c +index 94eb6b1..5ad92da 100644 +--- erts/emulator/sys/unix/erl_child_setup.c ++++ erts/emulator/sys/unix/erl_child_setup.c +@@ -101,7 +101,9 @@ main(int argc, char *argv[]) + if (sscanf(argv[CS_ARGV_FD_CR_IX], "%d:%d", &from, &to) != 2) + return 1; + +-#if defined(__ANDROID__) ++#if defined(HAVE_CLOSEFROM) ++ closefrom(from); ++#elif defined(__ANDROID__) + for (i = from; i <= to; i++) { + if (i!=__system_properties_fd) + (void) close(i); +@@ -109,13 +111,6 @@ main(int argc, char *argv[]) + #else + for (i = from; i <= to; i++) + (void) close(i); +-#endif /* __ANDROID__ */ +- +-#if defined(HAVE_CLOSEFROM) +- closefrom(from); +-#else +- for (i = from; i <= to; i++) +- (void) close(i); + #endif + + if (!(argv[CS_ARGV_WD_IX][0] == '.' && argv[CS_ARGV_WD_IX][1] == '\0') +@@ -147,8 +142,6 @@ main(int argc, char *argv[]) + return 1; + } + +- +- + #if defined(__ANDROID__) + int __system_properties_fd(void) + { +diff --git erts/emulator/sys/unix/sys.c erts/emulator/sys/unix/sys.c +index 0d677d5..cd87b32 100644 +--- erts/emulator/sys/unix/sys.c ++++ erts/emulator/sys/unix/sys.c +@@ -202,8 +202,6 @@ static erts_smp_atomic_t sys_misc_mem_sz; + #if defined(ERTS_SMP) + static void smp_sig_notify(char c); + static int sig_notify_fds[2] = {-1, -1}; +-#elif defined(USE_THREADS) +-static int async_fd[2]; + #endif + + #if CHLDWTHR || defined(ERTS_SMP) +@@ -246,6 +244,8 @@ static void note_child_death(int, int); + static void* child_waiter(void *); + #endif + ++static int crashdump_companion_cube_fd = -1; ++ + /********************* General functions ****************************/ + + /* This is used by both the drivers and general I/O, must be set early */ +@@ -575,6 +575,14 @@ erts_sys_pre_init(void) + close(fd); + } + ++ /* We need a file descriptor to close in the crashdump creation. ++ * We close this one to be sure we can get a fd for our real file ... ++ * so, we create one here ... a stone to carry all the way home. ++ */ ++ ++ crashdump_companion_cube_fd = open("/dev/null", O_RDONLY); ++ ++ /* don't lose it, there will be cake */ + } + + void +@@ -719,14 +727,13 @@ static ERTS_INLINE int + prepare_crash_dump(int secs) + { + #define NUFBUF (3) +- int i, max; ++ int i; + char env[21]; /* enough to hold any 64-bit integer */ + size_t envsz; + DeclareTmpHeapNoproc(heap,NUFBUF); + Port *heart_port; + Eterm *hp = heap; + Eterm list = NIL; +- int heart_fd[2] = {-1,-1}; + int has_heart = 0; + + UseTmpHeapNoproc(NUFBUF); +@@ -749,43 +756,22 @@ prepare_crash_dump(int secs) + alarm((unsigned int)secs); + } + ++ /* close all viable sockets via emergency close callbacks. ++ * Specifically we want to close epmd sockets. ++ */ ++ ++ erts_emergency_close_ports(); ++ + if (heart_port) { +- /* hearts input fd +- * We "know" drv_data is the in_fd since the port is started with read|write +- */ +- heart_fd[0] = (int)heart_port->drv_data; +- heart_fd[1] = (int)driver_data[heart_fd[0]].ofd; +- has_heart = 1; +- ++ has_heart = 1; + list = CONS(hp, make_small(8), list); hp += 2; +- + /* send to heart port, CMD = 8, i.e. prepare crash dump =o */ + erts_port_output(NULL, ERTS_PORT_SIG_FLG_FORCE_IMM_CALL, heart_port, + heart_port->common.id, list, NULL); + } + +- /* Make sure we unregister at epmd (unknown fd) and get at least +- one free filedescriptor (for erl_crash.dump) */ +- +- max = max_files; +- if (max < 1024) +- max = 1024; +- for (i = 3; i < max; i++) { +-#if defined(ERTS_SMP) +- /* We don't want to close the signal notification pipe... */ +- if (i == sig_notify_fds[0] || i == sig_notify_fds[1]) +- continue; +-#elif defined(USE_THREADS) +- /* We don't want to close the async notification pipe... */ +- if (i == async_fd[0] || i == async_fd[1]) +- continue; +-#endif +- /* We don't want to close our heart yet ... */ +- if (i == heart_fd[0] || i == heart_fd[1]) +- continue; +- +- close(i); +- } ++ /* Make sure we have a fd for our crashdump file. */ ++ close(crashdump_companion_cube_fd); + + envsz = sizeof(env); + i = erts_sys_getenv__("ERL_CRASH_DUMP_NICE", env, &envsz); +@@ -1574,9 +1560,13 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* op + goto child_error; + } + ++#if defined(HAVE_CLOSEFROM) ++ closefrom(opts->use_stdio ? 3 : 5); ++#else + for (i = opts->use_stdio ? 3 : 5; i < max_files; i++) + (void) close(i); +- ++#endif ++ + if (opts->wd && chdir(opts->wd) < 0) + goto child_error; + +diff --git erts/vsn.mk erts/vsn.mk +index d0dc8f7..e4b071b 100644 +--- erts/vsn.mk ++++ erts/vsn.mk +@@ -17,7 +17,7 @@ + # %CopyrightEnd% + # + +-VSN = 6.3 ++VSN = 6.3.1 + + # Port number 4365 in 4.2 + # Port number 4366 in 4.3 +diff --git lib/inets/doc/src/httpd.xml lib/inets/doc/src/httpd.xml +index 4ca038c..20c8a6b 100644 +--- lib/inets/doc/src/httpd.xml ++++ lib/inets/doc/src/httpd.xml +@@ -4,7 +4,7 @@ + <erlref> + <header> + <copyright> +- <year>1997</year><year>2013</year> ++ <year>1997</year><year>2015</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> +@@ -249,7 +249,16 @@ + <p>Limits the size of the message header of HTTP request. + Defaults to 10240. </p> + </item> +- ++ ++ <marker id="prop_max_content_length"></marker> ++ <tag>{max_content_length, integer()}</tag> ++ <item> ++ <p>Maximum Content-Length in an incoming request, in bytes. Requests ++ with content larger than this are answered with Status 413. ++ Defaults to 100000000 (100 MB). ++ </p> ++ </item> ++ + <marker id="prop_max_uri"></marker> + <tag>{max_uri_size, integer()}</tag> + <item> +diff --git lib/inets/doc/src/notes.xml lib/inets/doc/src/notes.xml +index fb70344..7f73aa5 100644 +--- lib/inets/doc/src/notes.xml ++++ lib/inets/doc/src/notes.xml +@@ -32,7 +32,40 @@ + <file>notes.xml</file> + </header> + +- <section><title>Inets 5.10.4</title> ++ <section><title>Inets 5.10.5</title> ++ ++ <section><title>Fixed Bugs and Malfunctions</title> ++ <list> ++ <item> ++ <p> ++ mod_alias now handles https-URIs properly</p> ++ <p> ++ Consistent view of configuration parameter ++ keep_alive_timeout, should be presented in the ++ httpd:info/[1,2] function in the same unit as it is ++ inputted.</p> ++ <p> ++ Own Id: OTP-12436 Aux Id: seq12786 </p> ++ </item> ++ </list> ++ </section> ++ ++ ++ <section><title>Improvements and New Features</title> ++ <list> ++ <item> ++ <p> ++ Gracefully handle invalid content-lenght headers instead ++ of crashing in list_to_integer.</p> ++ <p> ++ Own Id: OTP-12429</p> ++ </item> ++ </list> ++ </section> ++ ++</section> ++ ++<section><title>Inets 5.10.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> +diff --git lib/inets/src/http_lib/http_internal.hrl lib/inets/src/http_lib/http_internal.hrl +index 53b776c..5442574 100644 +--- lib/inets/src/http_lib/http_internal.hrl ++++ lib/inets/src/http_lib/http_internal.hrl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 2002-2014. All Rights Reserved. ++%% Copyright Ericsson AB 2002-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -28,6 +28,7 @@ + -define(HTTP_MAX_URI_SIZE, nolimit). + -define(HTTP_MAX_VERSION_STRING, 8). + -define(HTTP_MAX_METHOD_STRING, 20). ++-define(HTTP_MAX_CONTENT_LENGTH, 100000000). + + -ifndef(HTTP_DEFAULT_SSL_KIND). + -define(HTTP_DEFAULT_SSL_KIND, essl). +diff --git lib/inets/src/http_lib/http_request.erl lib/inets/src/http_lib/http_request.erl +index f295453..a0833dd 100644 +--- lib/inets/src/http_lib/http_request.erl ++++ lib/inets/src/http_lib/http_request.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 2005-2014. All Rights Reserved. ++%% Copyright Ericsson AB 2005-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -21,8 +21,16 @@ + + -include("http_internal.hrl"). + +--export([headers/2, http_headers/1, is_absolut_uri/1]). ++-export([headers/2, http_headers/1, is_absolut_uri/1, key_value/1]). + ++ ++key_value(KeyValueStr) -> ++ case lists:splitwith(fun($:) -> false; (_) -> true end, KeyValueStr) of ++ {Key, [$: | Value]} -> ++ {http_util:to_lower(string:strip(Key)), string:strip(Value)}; ++ {_, []} -> ++ undefined ++ end. + %%------------------------------------------------------------------------- + %% headers(HeaderList, #http_request_h{}) -> #http_request_h{} + %% HeaderList - ["HeaderField:Value"] +@@ -34,14 +42,12 @@ + %%------------------------------------------------------------------------- + headers([], Headers) -> + Headers; +-headers([Header | Tail], Headers) -> +- case lists:splitwith(fun($:) -> false; (_) -> true end, Header) of +- {Key, [$: | Value]} -> +- headers(Tail, headers(http_util:to_lower(string:strip(Key)), +- string:strip(Value), Headers)); +- {_, []} -> +- headers(Tail, Headers) +- end. ++headers([{Key, Value} | Tail], Headers) -> ++ headers(Tail, headers(Key, Value, Headers)); ++headers([undefined], Headers) -> ++ Headers; ++headers(KeyValues, Headers) -> ++ headers([key_value(KeyValue) || KeyValue <- KeyValues], Headers). + + %%------------------------------------------------------------------------- + %% headers(#http_request_h{}) -> HeaderList +diff --git lib/inets/src/http_server/httpd_conf.erl lib/inets/src/http_server/httpd_conf.erl +index 27446ca..55698d5 100644 +--- lib/inets/src/http_server/httpd_conf.erl ++++ lib/inets/src/http_server/httpd_conf.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 1997-2013. All Rights Reserved. ++%% Copyright Ericsson AB 1997-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -205,13 +205,13 @@ load("MaxURISize " ++ MaxHeaderSize, []) -> + " is an invalid number of MaxHeaderSize")} + end; + +-load("MaxBodySize " ++ MaxBodySize, []) -> +- case make_integer(MaxBodySize) of ++load("MaxContentLength " ++ Max, []) -> ++ case make_integer(Max) of + {ok, Integer} -> +- {ok, [], {max_body_size,Integer}}; ++ {ok, [], {max_content_length, Integer}}; + {error, _} -> +- {error, ?NICE(clean(MaxBodySize) ++ +- " is an invalid number of MaxBodySize")} ++ {error, ?NICE(clean(Max) ++ ++ " is an invalid number of MaxContentLength")} + end; + + load("ServerName " ++ ServerName, []) -> +@@ -337,7 +337,7 @@ load("MaxKeepAliveRequest " ++ MaxRequests, []) -> + load("KeepAliveTimeout " ++ Timeout, []) -> + case make_integer(Timeout) of + {ok, Integer} -> +- {ok, [], {keep_alive_timeout, Integer*1000}}; ++ {ok, [], {keep_alive_timeout, Integer}}; + {error, _} -> + {error, ?NICE(clean(Timeout)++" is an invalid KeepAliveTimeout")} + end; +@@ -569,6 +569,12 @@ validate_config_params([{max_body_size, Value} | Rest]) + validate_config_params([{max_body_size, Value} | _]) -> + throw({max_body_size, Value}); + ++validate_config_params([{max_content_length, Value} | Rest]) ++ when is_integer(Value) andalso (Value > 0) -> ++ validate_config_params(Rest); ++validate_config_params([{max_content_length, Value} | _]) -> ++ throw({max_content_length, Value}); ++ + validate_config_params([{server_name, Value} | Rest]) + when is_list(Value) -> + validate_config_params(Rest); +@@ -635,7 +641,7 @@ validate_config_params([{max_keep_alive_request, Value} | Rest]) + when is_integer(Value) andalso (Value > 0) -> + validate_config_params(Rest); + validate_config_params([{max_keep_alive_request, Value} | _]) -> +- throw({max_header_size, Value}); ++ throw({max_keep_alive_request, Value}); + + validate_config_params([{keep_alive_timeout, Value} | Rest]) + when is_integer(Value) andalso (Value >= 0) -> +@@ -799,7 +805,7 @@ store({server_tokens, ServerTokens} = Entry, _ConfigList) -> + Server = server(ServerTokens), + {ok, [Entry, {server, Server}]}; + store({keep_alive_timeout, KeepAliveTimeout}, _ConfigList) -> +- {ok, {keep_alive_timeout, KeepAliveTimeout * 1000}}; ++ {ok, {keep_alive_timeout, KeepAliveTimeout}}; + store(ConfigListEntry, _ConfigList) -> + {ok, ConfigListEntry}. + +diff --git lib/inets/src/http_server/httpd_request.erl lib/inets/src/http_server/httpd_request.erl +index 712c735..6985065 100644 +--- lib/inets/src/http_server/httpd_request.erl ++++ lib/inets/src/http_server/httpd_request.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 2005-2014. All Rights Reserved. ++%% Copyright Ericsson AB 2005-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -118,18 +118,17 @@ validate(Method, Uri, Version) -> + %% create it. + %% ---------------------------------------------------------------------- + update_mod_data(ModData, Method, RequestURI, HTTPVersion, Headers)-> +- ParsedHeaders = tagup_header(Headers), +- PersistentConn = get_persistens(HTTPVersion, ParsedHeaders, ++ PersistentConn = get_persistens(HTTPVersion, Headers, + ModData#mod.config_db), + {ok, ModData#mod{data = [], + method = Method, + absolute_uri = format_absolute_uri(RequestURI, +- ParsedHeaders), ++ Headers), + request_uri = format_request_uri(RequestURI), + http_version = HTTPVersion, + request_line = Method ++ " " ++ RequestURI ++ + " " ++ HTTPVersion, +- parsed_header = ParsedHeaders, ++ parsed_header = Headers, + connection = PersistentConn}}. + + %%%======================================================================== +@@ -146,14 +145,14 @@ parse_method(_, _, _, Max, _, _) -> + %% We do not know the version of the client as it comes after the + %% method send the lowest version in the response so that the client + %% will be able to handle it. +- {error, {too_long, Max, 413, "Method unreasonably long"}, lowest_version()}. ++ {error, {size_error, Max, 413, "Method unreasonably long"}, lowest_version()}. + + parse_uri(_, _, Current, MaxURI, _, _) + when (Current > MaxURI) andalso (MaxURI =/= nolimit) -> + %% We do not know the version of the client as it comes after the + %% uri send the lowest version in the response so that the client + %% will be able to handle it. +- {error, {too_long, MaxURI, 414, "URI unreasonably long"},lowest_version()}; ++ {error, {size_error, MaxURI, 414, "URI unreasonably long"},lowest_version()}; + parse_uri(<<>>, URI, Current, Max, MaxSizes, Result) -> + {?MODULE, parse_uri, [URI, Current, Max, MaxSizes, Result]}; + parse_uri(<<?SP, Rest/binary>>, URI, _, _, MaxSizes, Result) -> +@@ -179,12 +178,12 @@ parse_version(<<?CR>> = Data, Version, Current, Max, MaxSizes, Result) -> + parse_version(<<Octet, Rest/binary>>, Version, Current, Max, MaxSizes, Result) when Current =< Max -> + parse_version(Rest, [Octet | Version], Current + 1, Max, MaxSizes, Result); + parse_version(_, _, _, Max,_,_) -> +- {error, {too_long, Max, 413, "Version string unreasonably long"}, lowest_version()}. ++ {error, {size_error, Max, 413, "Version string unreasonably long"}, lowest_version()}. + + parse_headers(_, _, _, Current, Max, _, Result) + when Max =/= nolimit andalso Current > Max -> + HttpVersion = lists:nth(3, lists:reverse(Result)), +- {error, {too_long, Max, 413, "Headers unreasonably long"}, HttpVersion}; ++ {error, {size_error, Max, 413, "Headers unreasonably long"}, HttpVersion}; + + parse_headers(<<>>, Header, Headers, Current, Max, MaxSizes, Result) -> + {?MODULE, parse_headers, [<<>>, Header, Headers, Current, Max, +@@ -204,14 +203,22 @@ parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, [], [], _, _, _, Result) -> + Result])), + {ok, NewResult}; + parse_headers(<<?CR,?LF,?CR,?LF,Body/binary>>, Header, Headers, _, _, +- _, Result) -> +- HTTPHeaders = [lists:reverse(Header) | Headers], +- RequestHeaderRcord = +- http_request:headers(HTTPHeaders, #http_request_h{}), +- NewResult = +- list_to_tuple(lists:reverse([Body, {RequestHeaderRcord, +- HTTPHeaders} | Result])), +- {ok, NewResult}; ++ MaxSizes, Result) -> ++ case http_request:key_value(lists:reverse(Header)) of ++ undefined -> %% Skip headers with missing : ++ {ok, list_to_tuple(lists:reverse([Body, {http_request:headers(Headers, #http_request_h{}), Headers} | Result]))}; ++ NewHeader -> ++ case check_header(NewHeader, MaxSizes) of ++ ok -> ++ {ok, list_to_tuple(lists:reverse([Body, {http_request:headers([NewHeader | Headers], ++ #http_request_h{}), ++ [NewHeader | Headers]} | Result]))}; ++ ++ {error, Reason} -> ++ HttpVersion = lists:nth(3, lists:reverse(Result)), ++ {error, Reason, HttpVersion} ++ end ++ end; + + parse_headers(<<?CR,?LF,?CR>> = Data, Header, Headers, Current, Max, + MaxSizes, Result) -> +@@ -243,8 +250,21 @@ parse_headers(<<?LF, Octet, Rest/binary>>, Header, Headers, Current, Max, + MaxSizes, Result); + parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, _, Max, + MaxSizes, Result) -> +- parse_headers(Rest, [Octet], [lists:reverse(Header) | Headers], +- 0, Max, MaxSizes, Result); ++ case http_request:key_value(lists:reverse(Header)) of ++ undefined -> %% Skip headers with missing : ++ parse_headers(Rest, [Octet], Headers, ++ 0, Max, MaxSizes, Result); ++ NewHeader -> ++ case check_header(NewHeader, MaxSizes) of ++ ok -> ++ parse_headers(Rest, [Octet], [NewHeader | Headers], ++ 0, Max, MaxSizes, Result); ++ {error, Reason} -> ++ HttpVersion = lists:nth(3, lists:reverse(Result)), ++ {error, Reason, HttpVersion} ++ end ++ end; ++ + parse_headers(<<?CR>> = Data, Header, Headers, Current, Max, + MaxSizes, Result) -> + {?MODULE, parse_headers, [Data, Header, Headers, Current, Max, +@@ -388,29 +408,25 @@ get_persistens(HTTPVersion,ParsedHeader,ConfigDB)-> + false + end. + +- +-%%---------------------------------------------------------------------- +-%% tagup_header +-%% +-%% Parses the header of a HTTP request and returns a key,value tuple +-%% list containing Name and Value of each header directive as of: +-%% +-%% Content-Type: multipart/mixed -> {"Content-Type", "multipart/mixed"} +-%% +-%% But in http/1.1 the field-names are case insencitive so now it must be +-%% Content-Type: multipart/mixed -> {"content-type", "multipart/mixed"} +-%% The standard furthermore says that leading and traling white space +-%% is not a part of the fieldvalue and shall therefore be removed. +-%%---------------------------------------------------------------------- +-tagup_header([]) -> []; +-tagup_header([Line|Rest]) -> [tag(Line, [])|tagup_header(Rest)]. +- +-tag([], Tag) -> +- {http_util:to_lower(lists:reverse(Tag)), ""}; +-tag([$:|Rest], Tag) -> +- {http_util:to_lower(lists:reverse(Tag)), string:strip(Rest)}; +-tag([Chr|Rest], Tag) -> +- tag(Rest, [Chr|Tag]). +- + lowest_version()-> + "HTTP/0.9". ++ ++check_header({"content-length", Value}, Maxsizes) -> ++ Max = proplists:get_value(max_content_length, Maxsizes), ++ MaxLen = length(integer_to_list(Max)), ++ case length(Value) =< MaxLen of ++ true -> ++ try ++ _ = list_to_integer(Value), ++ ok ++ catch _:_ -> ++ {error, {size_error, Max, 411, "content-length not an integer"}} ++ end; ++ false -> ++ {error, {size_error, Max, 413, "content-length unreasonably long"}} ++ end; ++check_header(_, _) -> ++ ok. ++ ++ ++ +diff --git lib/inets/src/http_server/httpd_request_handler.erl lib/inets/src/http_server/httpd_request_handler.erl +index 9bea58c..f7a9fe5 100644 +--- lib/inets/src/http_server/httpd_request_handler.erl ++++ lib/inets/src/http_server/httpd_request_handler.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 1997-2014. All Rights Reserved. ++%% Copyright Ericsson AB 1997-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -96,8 +96,9 @@ init([Manager, ConfigDB, AcceptTimeout]) -> + proc_lib:init_ack({ok, self()}), + + {SocketType, Socket} = await_socket_ownership_transfer(AcceptTimeout), +- +- KeepAliveTimeOut = httpd_util:lookup(ConfigDB, keep_alive_timeout, 150000), ++ ++ %%Timeout value is in seconds we want it in milliseconds ++ KeepAliveTimeOut = 1000 * httpd_util:lookup(ConfigDB, keep_alive_timeout, 150), + + case http_transport:negotiate(SocketType, Socket, ?HANDSHAKE_TIMEOUT) of + {error, _Error} -> +@@ -119,11 +120,15 @@ continue_init(Manager, ConfigDB, SocketType, Socket, TimeOut) -> + MaxHeaderSize = max_header_size(ConfigDB), + MaxURISize = max_uri_size(ConfigDB), + NrOfRequest = max_keep_alive_request(ConfigDB), +- ++ MaxContentLen = max_content_length(ConfigDB), ++ + {_, Status} = httpd_manager:new_connection(Manager), + + MFA = {httpd_request, parse, [[{max_uri, MaxURISize}, {max_header, MaxHeaderSize}, +- {max_version, ?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}]]}, ++ {max_version, ?HTTP_MAX_VERSION_STRING}, ++ {max_method, ?HTTP_MAX_METHOD_STRING}, ++ {max_content_length, MaxContentLen} ++ ]]}, + + State = #state{mod = Mod, + manager = Manager, +@@ -207,7 +212,7 @@ handle_info({Proto, Socket, Data}, + set_new_data_size(cancel_request_timeout(State), NewDataSize) + end, + handle_http_msg(Result, NewState); +- {error, {too_long, MaxSize, ErrCode, ErrStr}, Version} -> ++ {error, {size_error, MaxSize, ErrCode, ErrStr}, Version} -> + NewModData = ModData#mod{http_version = Version}, + httpd_response:send_status(NewModData, ErrCode, ErrStr), + Reason = io_lib:format("~p: ~p max size is ~p~n", +@@ -444,8 +449,7 @@ handle_body(#state{headers = Headers, body = Body, mod = ModData} = State, + error_log(Reason, ModData), + {stop, normal, State#state{response_sent = true}}; + _ -> +- Length = +- list_to_integer(Headers#http_request_h.'content-length'), ++ Length = list_to_integer(Headers#http_request_h.'content-length'), + case ((Length =< MaxBodySize) or (MaxBodySize == nolimit)) of + true -> + case httpd_request:whole_body(Body, Length) of +@@ -454,7 +458,7 @@ handle_body(#state{headers = Headers, body = Body, mod = ModData} = State, + ModData#mod.socket, + [{active, once}]), + {noreply, State#state{mfa = +- {Module, Function, Args}}}; ++ {Module, Function, Args}}}; + + {ok, NewBody} -> + handle_response( +@@ -471,7 +475,7 @@ handle_body(#state{headers = Headers, body = Body, mod = ModData} = State, + handle_expect(#state{headers = Headers, mod = + #mod{config_db = ConfigDB} = ModData} = State, + MaxBodySize) -> +- Length = Headers#http_request_h.'content-length', ++ Length = list_to_integer(Headers#http_request_h.'content-length'), + case expect(Headers, ModData#mod.http_version, ConfigDB) of + continue when (MaxBodySize > Length) orelse (MaxBodySize =:= nolimit) -> + httpd_response:send_status(ModData, 100, ""), +@@ -545,9 +549,13 @@ handle_next_request(#state{mod = #mod{connection = true} = ModData, + init_data = ModData#mod.init_data}, + MaxHeaderSize = max_header_size(ModData#mod.config_db), + MaxURISize = max_uri_size(ModData#mod.config_db), ++ MaxContentLen = max_content_length(ModData#mod.config_db), + + MFA = {httpd_request, parse, [[{max_uri, MaxURISize}, {max_header, MaxHeaderSize}, +- {max_version, ?HTTP_MAX_VERSION_STRING}, {max_method, ?HTTP_MAX_METHOD_STRING}]]}, ++ {max_version, ?HTTP_MAX_VERSION_STRING}, ++ {max_method, ?HTTP_MAX_METHOD_STRING}, ++ {max_content_length, MaxContentLen} ++ ]]}, + TmpState = State#state{mod = NewModData, + mfa = MFA, + max_keep_alive_request = decrease(Max), +@@ -630,3 +638,5 @@ max_body_size(ConfigDB) -> + max_keep_alive_request(ConfigDB) -> + httpd_util:lookup(ConfigDB, max_keep_alive_request, infinity). + ++max_content_length(ConfigDB) -> ++ httpd_util:lookup(ConfigDB, max_content_length, ?HTTP_MAX_CONTENT_LENGTH). +diff --git lib/inets/src/http_server/mod_alias.erl lib/inets/src/http_server/mod_alias.erl +index 0b9fe4c..5039cd5 100644 +--- lib/inets/src/http_server/mod_alias.erl ++++ lib/inets/src/http_server/mod_alias.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 1997-2010. All Rights Reserved. ++%% Copyright Ericsson AB 1997-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -55,6 +55,7 @@ do(#mod{data = Data} = Info) -> + + do_alias(#mod{config_db = ConfigDB, + request_uri = ReqURI, ++ socket_type = SocketType, + data = Data}) -> + {ShortPath, Path, AfterPath} = + real_name(ConfigDB, ReqURI, which_alias(ConfigDB)), +@@ -70,8 +71,9 @@ do_alias(#mod{config_db = ConfigDB, + (LastChar =/= $/)) -> + ?hdrt("directory and last-char is a /", []), + ServerName = which_server_name(ConfigDB), +- Port = port_string( which_port(ConfigDB) ), +- URL = "http://" ++ ServerName ++ Port ++ ReqURI ++ "/", ++ Port = port_string(which_port(ConfigDB)), ++ Protocol = get_protocol(SocketType), ++ URL = Protocol ++ ServerName ++ Port ++ ReqURI ++ "/", + ReasonPhrase = httpd_util:reason_phrase(301), + Message = httpd_util:message(301, URL, ConfigDB), + {proceed, +@@ -94,6 +96,12 @@ port_string(80) -> + port_string(Port) -> + ":" ++ integer_to_list(Port). + ++get_protocol(ip_comm) -> ++ "http://"; ++get_protocol(_) -> ++ %% Should clean up to have only one ssl type essl vs ssl is not relevant any more ++ "https://". ++ + %% real_name + + real_name(ConfigDB, RequestURI, []) -> +diff --git lib/inets/test/http_format_SUITE.erl lib/inets/test/http_format_SUITE.erl +index d4a3f28..5952e9f 100644 +--- lib/inets/test/http_format_SUITE.erl ++++ lib/inets/test/http_format_SUITE.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 2004-2014. All Rights Reserved. ++%% Copyright Ericsson AB 2004-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -355,10 +355,12 @@ http_request(Config) when is_list(Config) -> + "http://www.erlang.org", + "HTTP/1.1", + {#http_request_h{host = "www.erlang.org", te = []}, +- ["te: ","host:www.erlang.org"]}, <<>>} = ++ [{"te", []}, {"host", "www.erlang.org"}]}, <<>>} = + parse(httpd_request, parse, [[{max_header, ?HTTP_MAX_HEADER_SIZE}, + {max_version, ?HTTP_MAX_VERSION_STRING}, +- {max_method, ?HTTP_MAX_METHOD_STRING}]], ++ {max_method, ?HTTP_MAX_METHOD_STRING}, ++ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} ++ ]], + HttpHead), + + HttpHead1 = ["GET http://www.erlang.org HTTP/1.1" ++ +@@ -369,7 +371,9 @@ http_request(Config) when is_list(Config) -> + {#http_request_h{}, []}, <<>>} = + parse(httpd_request, parse, [[{max_header, ?HTTP_MAX_HEADER_SIZE}, + {max_version, ?HTTP_MAX_VERSION_STRING}, +- {max_method, ?HTTP_MAX_METHOD_STRING}]], HttpHead1), ++ {max_method, ?HTTP_MAX_METHOD_STRING}, ++ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} ++ ]], HttpHead1), + + + HttpHead2 = ["GET http://www.erlang.org HTTP/1.1" ++ +@@ -380,7 +384,9 @@ http_request(Config) when is_list(Config) -> + {#http_request_h{}, []}, <<>>} = + parse(httpd_request, parse, [[{max_header, ?HTTP_MAX_HEADER_SIZE}, + {max_version, ?HTTP_MAX_VERSION_STRING}, +- {max_method, ?HTTP_MAX_METHOD_STRING}]], HttpHead2), ++ {max_method, ?HTTP_MAX_METHOD_STRING}, ++ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} ++ ]], HttpHead2), + + %% Note the following body is not related to the headers above + HttpBody = ["<HTML>\n<HEAD>\n<TITLE> dummy </TITLE>\n</HEAD>\n<BODY>\n", +diff --git lib/inets/test/httpc_SUITE.erl lib/inets/test/httpc_SUITE.erl +index c535d59..390f2bb 100644 +--- lib/inets/test/httpc_SUITE.erl ++++ lib/inets/test/httpc_SUITE.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 2004-2014. All Rights Reserved. ++%% Copyright Ericsson AB 2004-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -1246,8 +1246,9 @@ dummy_server_init(Caller, ip_comm, Inet, _) -> + dummy_ipcomm_server_loop({httpd_request, parse, [[{max_uri, ?HTTP_MAX_URI_SIZE}, + {max_header, ?HTTP_MAX_HEADER_SIZE}, + {max_version,?HTTP_MAX_VERSION_STRING}, +- {max_method, ?HTTP_MAX_METHOD_STRING}]]}, +- [], ListenSocket); ++ {max_method, ?HTTP_MAX_METHOD_STRING}, ++ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH}]]}, ++ [], ListenSocket); + + dummy_server_init(Caller, ssl, Inet, SSLOptions) -> + BaseOpts = [binary, {reuseaddr,true}, {active, false} | +@@ -1261,7 +1262,9 @@ dummy_ssl_server_init(Caller, BaseOpts, Inet) -> + dummy_ssl_server_loop({httpd_request, parse, [[{max_uri, ?HTTP_MAX_URI_SIZE}, + {max_method, ?HTTP_MAX_METHOD_STRING}, + {max_version,?HTTP_MAX_VERSION_STRING}, +- {max_method, ?HTTP_MAX_METHOD_STRING}]]}, ++ {max_method, ?HTTP_MAX_METHOD_STRING}, ++ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} ++ ]]}, + [], ListenSocket). + + dummy_ipcomm_server_loop(MFA, Handlers, ListenSocket) -> +@@ -1338,16 +1341,20 @@ handle_request(Module, Function, Args, Socket) -> + stop -> + stop; + <<>> -> +- {httpd_request, parse, [[<<>>, [{max_uri, ?HTTP_MAX_URI_SIZE}, ++ {httpd_request, parse, [[{max_uri,?HTTP_MAX_URI_SIZE}, + {max_header, ?HTTP_MAX_HEADER_SIZE}, + {max_version,?HTTP_MAX_VERSION_STRING}, +- {max_method, ?HTTP_MAX_METHOD_STRING}]]]}; ++ {max_method, ?HTTP_MAX_METHOD_STRING}, ++ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} ++ ]]}; + Data -> + handle_request(httpd_request, parse, + [Data, [{max_uri, ?HTTP_MAX_URI_SIZE}, +- {max_header, ?HTTP_MAX_HEADER_SIZE}, +- {max_version,?HTTP_MAX_VERSION_STRING}, +- {max_method, ?HTTP_MAX_METHOD_STRING}]], Socket) ++ {max_header, ?HTTP_MAX_HEADER_SIZE}, ++ {max_version,?HTTP_MAX_VERSION_STRING}, ++ {max_method, ?HTTP_MAX_METHOD_STRING}, ++ {max_content_length, ?HTTP_MAX_CONTENT_LENGTH} ++ ]], Socket) + end; + NewMFA -> + NewMFA +@@ -1437,7 +1444,7 @@ dummy_ssl_server_hang_loop(_) -> + + ensure_host_header_with_port([]) -> + false; +-ensure_host_header_with_port(["host: " ++ Host| _]) -> ++ensure_host_header_with_port([{"host", Host}| _]) -> + case string:tokens(Host, [$:]) of + [_ActualHost, _Port] -> + true; +@@ -1449,7 +1456,7 @@ ensure_host_header_with_port([_|T]) -> + + auth_header([]) -> + auth_header_not_found; +-auth_header(["authorization:" ++ Value | _]) -> ++auth_header([{"authorization", Value} | _]) -> + {ok, string:strip(Value)}; + auth_header([_ | Tail]) -> + auth_header(Tail). +@@ -1466,7 +1473,7 @@ handle_auth("Basic " ++ UserInfo, Challange, DefaultResponse) -> + + check_cookie([]) -> + ct:fail(no_cookie_header); +-check_cookie(["cookie:" ++ _Value | _]) -> ++check_cookie([{"cookie", _} | _]) -> + ok; + check_cookie([_Head | Tail]) -> + check_cookie(Tail). +diff --git lib/inets/test/httpd_SUITE.erl lib/inets/test/httpd_SUITE.erl +index 4010597..342004f 100644 +--- lib/inets/test/httpd_SUITE.erl ++++ lib/inets/test/httpd_SUITE.erl +@@ -1,7 +1,7 @@ + %% + %% %CopyrightBegin% + %% +-%% Copyright Ericsson AB 2013-2014. All Rights Reserved. ++%% Copyright Ericsson AB 2013-2015. All Rights Reserved. + %% + %% The contents of this file are subject to the Erlang Public License, + %% Version 1.1, (the "License"); you may not use this file except in +@@ -132,6 +132,7 @@ http_get() -> + bad_hex, + missing_CR, + max_header, ++ max_content_length, + ipv6 + ]. + +@@ -979,13 +980,22 @@ max_header(Config) when is_list(Config) -> + Host = ?config(host, Config), + case Version of + "HTTP/0.9" -> +- {skip, no_implemented}; ++ {skip, not_implemented}; + _ -> + dos_hostname(?config(type, Config), ?config(port, Config), Host, + ?config(node, Config), Version, ?MAX_HEADER_SIZE) + end. + + %%------------------------------------------------------------------------- ++max_content_length() -> ++ ["Denial Of Service (DOS) attack, prevented by max_content_length"]. ++max_content_length(Config) when is_list(Config) -> ++ Version = ?config(http_version, Config), ++ Host = ?config(host, Config), ++ garbage_content_length(?config(type, Config), ?config(port, Config), Host, ++ ?config(node, Config), Version). ++ ++%%------------------------------------------------------------------------- + security_1_1(Config) when is_list(Config) -> + security([{http_version, "HTTP/1.1"} | Config]). + +@@ -1368,7 +1378,9 @@ server_config(http_reload, Config) -> + server_config(https_reload, Config) -> + [{keep_alive_timeout, 2}] ++ server_config(https, Config); + server_config(http_limit, Config) -> +- [{max_clients, 1}] ++ server_config(http, Config); ++ [{max_clients, 1}, ++ %% Make sure option checking code is run ++ {max_content_length, 100000002}] ++ server_config(http, Config); + server_config(https_limit, Config) -> + [{max_clients, 1}] ++ server_config(https, Config); + server_config(http_basic_auth, Config) -> +@@ -1814,7 +1826,7 @@ dos_hostname(Type, Port, Host, Node, Version, Max) -> + + ok = httpd_test_lib:verify_request(Type, Host, Port, Node, + dos_hostname_request(TooLongHeader, Version), +- [{statuscode, dos_code(Version)}, ++ [{statuscode, request_entity_too_large_code(Version)}, + {version, Version}]). + dos_hostname_request(Host, Version) -> + dos_http_request("GET / ", Version, Host). +@@ -1824,11 +1836,32 @@ dos_http_request(Request, "HTTP/1.1" = Version, Host) -> + dos_http_request(Request, Version, Host) -> + Request ++ Version ++ "\r\nhost:" ++ Host ++ "\r\n\r\n". + +-dos_code("HTTP/1.0") -> ++request_entity_too_large_code("HTTP/1.0") -> + 403; %% 413 not defined in HTTP/1.0 +-dos_code(_) -> ++request_entity_too_large_code(_) -> + 413. + ++length_required_code("HTTP/1.0") -> ++ 403; %% 411 not defined in HTTP/1.0 ++length_required_code(_) -> ++ 411. ++ ++garbage_content_length(Type, Port, Host, Node, Version) -> ++ ok = httpd_test_lib:verify_request(Type, Host, Port, Node, ++ garbage_content_length_request("GET / ", Version, Host, "aaaa"), ++ [{statuscode, length_required_code(Version)}, ++ {version, Version}]), ++ ok = httpd_test_lib:verify_request(Type, Host, Port, Node, ++ garbage_content_length_request("GET / ", Version, Host, ++ lists:duplicate($a, 100)), ++ [{statuscode, request_entity_too_large_code(Version)}, ++ {version, Version}]). ++ ++garbage_content_length_request(Request, Version, Host, Garbage) -> ++ http_request(Request, Version, Host, ++ {"content-length:" ++ Garbage, "Body with garbage content length indicator"}). ++ ++ + update_password(Node, ServerRoot, _Address, Port, AuthPrefix, Dir, Old, New)-> + Directory = filename:join([ServerRoot, "htdocs", AuthPrefix ++ Dir]), + rpc:call(Node, mod_auth, update_password, +diff --git lib/inets/vsn.mk lib/inets/vsn.mk +index dbae5e4..7d11916 100644 +--- lib/inets/vsn.mk ++++ lib/inets/vsn.mk +@@ -18,6 +18,6 @@ + # %CopyrightEnd% + + APPLICATION = inets +-INETS_VSN = 5.10.4 ++INETS_VSN = 5.10.5 + PRE_VSN = + APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" +diff --git otp_versions.table otp_versions.table +index 5753385..41c05e7 100644 +--- otp_versions.table ++++ otp_versions.table +@@ -1,3 +1,4 @@ ++OTP-17.4.1 : erts-6.3.1 inets-5.10.5 # asn1-3.0.3 common_test-1.9 compiler-5.0.3 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.2 ic-4.3.6 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.15 sasl-2.4.1 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 typer-0.9.8 webtool-0.8.10 wx-1.3.2 xmerl-1.3.7 : + OTP-17.4 : asn1-3.0.3 common_test-1.9 compiler-5.0.3 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.3 eunit-2.2.9 hipe-3.11.2 inets-5.10.4 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 runtime_tools-1.8.15 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 wx-1.3.2 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 et-1.5 gs-1.5.16 ic-4.3.6 orber-3.7.1 os_mon-2.3 ose-1.0.2 public_key-0.22.1 reltool-0.6.6 sasl-2.4.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 : + OTP-17.3.4 : erts-6.2.1 # asn1-3.0.2 common_test-1.8.2 compiler-5.0.2 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.1 debugger-4.0.1 dialyzer-2.7.2 diameter-1.7.1 edoc-0.7.15 eldap-1.0.4 erl_docgen-0.3.6 erl_interface-3.7.19 et-1.5 eunit-2.2.8 gs-1.5.16 hipe-3.11.1 ic-4.3.6 inets-5.10.3 jinterface-1.5.11 kernel-3.0.3 megaco-3.17.2 mnesia-4.12.3 observer-2.0.2 odbc-2.10.21 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.9 parsetools-2.0.11 percept-0.8.9 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.14 sasl-2.4.1 snmp-5.1 ssh-3.0.8 ssl-5.3.7 stdlib-2.2 syntax_tools-1.6.16 test_server-3.7.1 tools-2.7 typer-0.9.8 webtool-0.8.10 wx-1.3.1 xmerl-1.3.7 : + OTP-17.3.3 : ssh-3.0.8 # asn1-3.0.2 common_test-1.8.2 compiler-5.0.2 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.1 debugger-4.0.1 dialyzer-2.7.2 diameter-1.7.1 edoc-0.7.15 eldap-1.0.4 erl_docgen-0.3.6 erl_interface-3.7.19 erts-6.2 et-1.5 eunit-2.2.8 gs-1.5.16 hipe-3.11.1 ic-4.3.6 inets-5.10.3 jinterface-1.5.11 kernel-3.0.3 megaco-3.17.2 mnesia-4.12.3 observer-2.0.2 odbc-2.10.21 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.9 parsetools-2.0.11 percept-0.8.9 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.14 sasl-2.4.1 snmp-5.1 ssl-5.3.7 stdlib-2.2 syntax_tools-1.6.16 test_server-3.7.1 tools-2.7 typer-0.9.8 webtool-0.8.10 wx-1.3.1 xmerl-1.3.7 : |