Hi, as requested by many, the following simple diff allows to change the default media type globally or per location, eg. default type text/plain
Note that this diff conflicts with florian's HSTS diff, we'll reassign the flag in httpd.h based on which one goes in first. OK? Reyk Index: config.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/config.c,v retrieving revision 1.39 diff -u -p -u -p -r1.39 config.c --- config.c 15 Jul 2015 16:00:39 -0000 1.39 +++ config.c 18 Jul 2015 00:54:45 -0000 @@ -436,6 +436,13 @@ config_getserver_config(struct httpd *en goto fail; } + f = SRVFLAG_DEFAULT_TYPE; + if ((srv_conf->flags & f) == 0) { + srv_conf->flags |= parent->flags & f; + memcpy(&srv_conf->default_type, + &parent->default_type, sizeof(struct media_type)); + } + memcpy(&srv_conf->timeout, &parent->timeout, sizeof(srv_conf->timeout)); srv_conf->maxrequests = parent->maxrequests; Index: httpd.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/httpd.c,v retrieving revision 1.37 diff -u -p -u -p -r1.37 httpd.c --- httpd.c 3 Jun 2015 02:24:36 -0000 1.37 +++ httpd.c 18 Jul 2015 00:54:45 -0000 @@ -1217,7 +1217,7 @@ media_purge(struct mediatypes *types) } struct media_type * -media_find(struct mediatypes *types, char *file) +media_find(struct mediatypes *types, const char *file) { struct media_type *match, media; char *p; @@ -1239,6 +1239,21 @@ media_find(struct mediatypes *types, cha match = RB_FIND(mediatypes, types, &media); return (match); +} + +struct media_type * +media_find_config(struct httpd *env, struct server_config *srv_conf, + const char *file) +{ + struct media_type *match; + + if ((match = media_find(env->sc_mediatypes, file)) != NULL) + return (match); + else if (srv_conf->flags & SRVFLAG_DEFAULT_TYPE) + return (&srv_conf->default_type); + + /* fallback to the global default type */ + return (&env->sc_default_type); } int Index: httpd.conf.5 =================================================================== RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v retrieving revision 1.64 diff -u -p -u -p -r1.64 httpd.conf.5 --- httpd.conf.5 15 Jul 2015 17:10:47 -0000 1.64 +++ httpd.conf.5 18 Jul 2015 00:54:45 -0000 @@ -112,6 +112,15 @@ directory. If not specified, it defaults to .Pa /var/www , the home directory of the www user. +.It Ic default type Ar type/subtype +Set the default media type that is used if the media type for a +specified extension is not found in the configured types or for files +without a file extension; +see the +.Sx TYPES +section below. +If not specified, the default type is set to +.Ar application/octet-stream . .It Ic logdir Ar directory Specifies the full path of the directory in which log files will be written. If not specified, it defaults to @@ -236,6 +245,9 @@ Specify the inactivity timeout in second The default timeout is 600 seconds (10 minutes). The maximum is 2147483647 seconds (68 years). .El +.It Ic default type Ar type/subtype +Set the default media type for the specified location, +overwriting the global setting. .It Ic directory Ar option Set the specified options when serving or accessing directories. Valid options are: Index: httpd.h =================================================================== RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v retrieving revision 1.88 diff -u -p -u -p -r1.88 httpd.h --- httpd.h 16 Jul 2015 16:29:25 -0000 1.88 +++ httpd.h 18 Jul 2015 00:54:45 -0000 @@ -48,6 +48,7 @@ #define HTTPD_LOGROOT "/logs" #define HTTPD_ACCESS_LOG "access.log" #define HTTPD_ERROR_LOG "error.log" +#define HTTPD_DEFAULT_TYPE { "bin", "application", "octet-stream", NULL } #define HTTPD_LOGVIS VIS_NL|VIS_TAB|VIS_CSTYLE #define HTTPD_TLS_CERT "/etc/ssl/server.crt" #define HTTPD_TLS_KEY "/etc/ssl/private/server.key" @@ -351,13 +352,14 @@ SPLAY_HEAD(client_tree, client); #define SRVFLAG_NO_BLOCK 0x00080000 #define SRVFLAG_LOCATION_MATCH 0x00100000 #define SRVFLAG_SERVER_MATCH 0x00200000 +#define SRVFLAG_DEFAULT_TYPE 0x00400000 #define SRVFLAG_BITS \ "\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX" \ "\05ROOT\06LOCATION\07FCGI\10NO_FCGI\11LOG\12NO_LOG\13SOCKET" \ "\14SYSLOG\15NO_SYSLOG\16TLS\17ACCESS_LOG\20ERROR_LOG" \ "\21AUTH\22NO_AUTH\23BLOCK\24NO_BLOCK\25LOCATION_MATCH" \ - "\26SERVER_MATCH" + "\26SERVER_MATCH\27DEFAULT_TYPE" #define TCPFLAG_NODELAY 0x01 #define TCPFLAG_NNODELAY 0x02 @@ -387,6 +389,15 @@ struct log_file { }; TAILQ_HEAD(log_files, log_file) log_files; +struct media_type { + char media_name[MEDIATYPE_NAMEMAX]; + char media_type[MEDIATYPE_TYPEMAX]; + char media_subtype[MEDIATYPE_TYPEMAX]; + char *media_encoding; + RB_ENTRY(media_type) media_entry; +}; +RB_HEAD(mediatypes, media_type); + struct auth { char auth_htpasswd[PATH_MAX]; u_int32_t auth_id; @@ -404,6 +415,7 @@ struct server_config { char socket[PATH_MAX]; char accesslog[NAME_MAX]; char errorlog[NAME_MAX]; + struct media_type default_type; in_port_t port; struct sockaddr_storage ss; @@ -473,15 +485,6 @@ struct server { }; TAILQ_HEAD(serverlist, server); -struct media_type { - char media_name[MEDIATYPE_NAMEMAX]; - char media_type[MEDIATYPE_TYPEMAX]; - char media_subtype[MEDIATYPE_TYPEMAX]; - char *media_encoding; - RB_ENTRY(media_type) media_entry; -}; -RB_HEAD(mediatypes, media_type); - struct httpd { u_int8_t sc_opts; u_int32_t sc_flags; @@ -495,6 +498,7 @@ struct httpd { struct serverlist *sc_servers; struct mediatypes *sc_mediatypes; + struct media_type sc_default_type; struct serverauth *sc_auth; struct privsep *sc_ps; @@ -639,7 +643,10 @@ struct media_type void media_delete(struct mediatypes *, struct media_type *); void media_purge(struct mediatypes *); struct media_type * - media_find(struct mediatypes *, char *); + media_find(struct mediatypes *, const char *); +struct media_type * + media_find_config(struct httpd *, struct server_config *, + const char *); int media_cmp(struct media_type *, struct media_type *); RB_PROTOTYPE(kvtree, kv, kv_node, kv_cmp); RB_PROTOTYPE(mediatypes, media_type, media_entry, media_cmp); Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/httpd/parse.y,v retrieving revision 1.70 diff -u -p -u -p -r1.70 parse.y --- parse.y 16 Jul 2015 19:05:28 -0000 1.70 +++ parse.y 18 Jul 2015 00:54:45 -0000 @@ -133,8 +133,8 @@ typedef struct { %token COMBINED CONNECTION DHE DIRECTORY ECDHE ERR FCGI INDEX IP KEY LISTEN %token LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY ON PORT PREFORK PROTOCOLS %token REQUEST REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TIMEOUT -%token TLS TYPES -%token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS +%token TLS TYPE TYPES +%token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS DEFAULT %token <v.string> STRING %token <v.number> NUMBER %type <v.port> port @@ -198,6 +198,10 @@ main : PREFORK NUMBER { | LOGDIR STRING { conf->sc_logdir = $2; } + | DEFAULT TYPE mediastring { + memcpy(&conf->sc_default_type, &media, + sizeof(struct media_type)); + } ; server : SERVER optmatch STRING { @@ -555,6 +559,11 @@ serveroptsl : LISTEN ON STRING opttls po srv_conf = &parentsrv->srv_conf; parentsrv = NULL; } + | DEFAULT TYPE mediastring { + srv_conf->flags |= SRVFLAG_DEFAULT_TYPE; + memcpy(&srv_conf->default_type, &media, + sizeof(struct media_type)); + } | include ; @@ -961,7 +970,11 @@ mediaopts_l : mediaopts_l mediaoptsl nl | mediaoptsl nl ; -mediaoptsl : STRING '/' STRING { +mediaoptsl : mediastring medianames_l optsemicolon + | include + ; + +mediastring : STRING '/' STRING { if (strlcpy(media.media_type, $1, sizeof(media.media_type)) >= sizeof(media.media_type) || @@ -975,8 +988,7 @@ mediaoptsl : STRING '/' STRING { } free($1); free($3); - } medianames_l optsemicolon - | include + } ; medianames_l : medianames_l medianamesl @@ -1109,6 +1121,7 @@ lookup(char *s) { "combined", COMBINED }, { "common", COMMON }, { "connection", CONNECTION }, + { "default", DEFAULT }, { "dhe", DHE }, { "directory", DIRECTORY }, { "drop", DROP }, @@ -1145,6 +1158,7 @@ lookup(char *s) { "tcp", TCP }, { "timeout", TIMEOUT }, { "tls", TLS }, + { "type", TYPE }, { "types", TYPES }, { "with", WITH } }; @@ -1472,13 +1486,17 @@ popfile(void) int parse_config(const char *filename, struct httpd *x_conf) { - struct sym *sym, *next; + struct sym *sym, *next; + struct media_type dflt = HTTPD_DEFAULT_TYPE; conf = x_conf; if (config_init(conf) == -1) { log_warn("%s: cannot initialize configuration", __func__); return (-1); } + + /* Set default media type */ + memcpy(&conf->sc_default_type, &dflt, sizeof(struct media_type)); errors = 0; Index: server_file.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/server_file.c,v retrieving revision 1.56 diff -u -p -u -p -r1.56 server_file.c --- server_file.c 17 Jul 2015 21:53:57 -0000 1.56 +++ server_file.c 18 Jul 2015 00:54:45 -0000 @@ -238,7 +238,7 @@ server_file_request(struct httpd *env, s if ((fd = open(path, O_RDONLY)) == -1) goto abort; - media = media_find(env->sc_mediatypes, path); + media = media_find_config(env, srv_conf, path); ret = server_response_http(clt, 200, media, st->st_size, MINIMUM(time(NULL), st->st_mtim.tv_sec)); switch (ret) { @@ -290,6 +290,7 @@ int server_partial_file_request(struct httpd *env, struct client *clt, char *path, struct stat *st, char *range_str) { + struct server_config *srv_conf = clt->clt_srv_conf; struct http_descriptor *resp = clt->clt_descresp; struct http_descriptor *desc = clt->clt_descreq; struct media_type *media, multipart_media; @@ -317,7 +318,7 @@ server_partial_file_request(struct httpd if ((fd = open(path, O_RDONLY)) == -1) goto abort; - media = media_find(env->sc_mediatypes, path); + media = media_find_config(env, srv_conf, path); if ((evb = evbuffer_new()) == NULL) { errstr = "failed to allocate file buffer"; goto abort; @@ -347,9 +348,7 @@ server_partial_file_request(struct httpd content_length += i; if ((i = evbuffer_add_printf(evb, "Content-Type: %s/%s\r\n", - media == NULL ? "application" : media->media_type, - media == NULL ? - "octet-stream" : media->media_subtype)) == -1) + media->media_type, media->media_subtype)) == -1) goto abort; content_length += i; @@ -542,7 +541,7 @@ server_file_index(struct httpd *env, str close(fd); fd = -1; - media = media_find(env->sc_mediatypes, "index.html"); + media = media_find_config(env, srv_conf, "index.html"); ret = server_response_http(clt, 200, media, EVBUFFER_LENGTH(evb), dir_mtime); switch (ret) { Index: server_http.c =================================================================== RCS file: /cvs/src/usr.sbin/httpd/server_http.c,v retrieving revision 1.89 diff -u -p -u -p -r1.89 server_http.c --- server_http.c 16 Jul 2015 19:05:28 -0000 1.89 +++ server_http.c 18 Jul 2015 00:54:45 -0000 @@ -1216,7 +1216,8 @@ server_response_http(struct client *clt, struct kv *ct, *cl; char tmbuf[32]; - if (desc == NULL || (error = server_httperror_byid(code)) == NULL) + if (desc == NULL || media == NULL || + (error = server_httperror_byid(code)) == NULL) return (-1); if (server_log_http(clt, code, size) == -1) @@ -1241,9 +1242,7 @@ server_response_http(struct client *clt, /* Set media type */ if ((ct = kv_add(&resp->http_headers, "Content-Type", NULL)) == NULL || - kv_set(ct, "%s/%s", - media == NULL ? "application" : media->media_type, - media == NULL ? "octet-stream" : media->media_subtype) == -1) + kv_set(ct, "%s/%s", media->media_type, media->media_subtype) == -1) return (-1); /* Set content length, if specified */