package ocsigenserver

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file ocsigen_charset_mime.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
(* Ocsigen
 * http://www.ocsigen.org
 * ocsigen_charset_mime.ml Copyright (C) 2008
 * Boris Yakobowski
 * Laboratoire PPS - CNRS Université Paris Diderot
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, with linking exception;
 * either version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)

open Ocsigen_lib

module MapString = Map.Make(String)
type extension = string
type filename = string
type file = string

let section = Lwt_log.Section.make "ocsigen:mimetype"

type 'a assoc_item =
  | Extension of extension * 'a
  | File of filename * 'a
  | Regexp of Pcre.regexp * 'a
  | Map of 'a MapString.t

type 'a assoc = {
  assoc_list: 'a assoc_item list;
  assoc_default: 'a
}

let find_in_assoc file assoc =
  let filename = Filename.basename file in
  let ext =
    try String.lowercase_ascii (Filename.extension_no_directory file)
    with Not_found -> ""
  in
  let rec aux = function
    | [] -> assoc.assoc_default
    | Extension (ext', v) :: q ->
      if ext = ext' then v else aux q
    | File (filename', v) :: q ->
      if filename = filename' then v else aux q
    | Regexp (reg, v) :: q ->
      if Netstring_pcre.string_match reg file 0 <> None then v else aux q
    | Map m :: q ->
      try MapString.find ext m
      with Not_found -> aux q
  in
  aux assoc.assoc_list


let default assoc = assoc.assoc_default

let set_default assoc default = { assoc with assoc_default = default }

let update_ext assoc (ext : extension) v =
  { assoc with assoc_list =
                 Extension (String.lowercase_ascii ext, v) :: assoc.assoc_list}

let update_file assoc (file : filename) v =
  { assoc with assoc_list = File (file, v) :: assoc.assoc_list}

let update_regexp assoc r v =
  { assoc with assoc_list = Regexp (r, v) :: assoc.assoc_list}


let empty default () = {
  assoc_list = [];
  assoc_default = default
}


(* Handling of charset and mime ; specific values and declarations *)

type charset = string
type mime_type = string

type charset_assoc = charset assoc
type mime_assoc = mime_type assoc

let no_charset : charset = ""
let default_mime_type : mime_type = "application/octet-stream"

let empty_charset_assoc ?(default=no_charset) = empty default
let empty_mime_assoc ?(default=default_mime_type) = empty default

(* Generic functions *)

let default_charset = default
let default_mime = default

let update_charset_ext = update_ext
let update_mime_ext = update_ext

let update_charset_file = update_file
let update_mime_file = update_file

let update_charset_regexp = update_regexp
let update_mime_regexp = update_regexp

let set_default_mime = set_default
let set_default_charset = set_default

let find_charset = find_in_assoc
let find_mime = find_in_assoc


(* Specific handling of content-type *)


let parse_mime_types ~filename : mime_type assoc =
  let rec read_and_split mimemap in_ch =
    try
      let line = input_line in_ch in
      let line_upto =
        try
          let upto = String.index line '#' in
          String.sub line 0 upto
        with Not_found -> line
      in
      let strlist =
        Netstring_pcre.split (Netstring_pcre.regexp "\\s+") line_upto
      in
      match  strlist with
      | [] | [_] -> (* No extension on this line *) read_and_split mimemap in_ch
      | mime :: extensions ->
        let mimemap =
          List.fold_left (fun mimemap ext ->
              MapString.add ext mime mimemap) mimemap extensions
        in
        read_and_split mimemap in_ch
    with End_of_file -> mimemap
  in
  { assoc_list =
      [ Map(try
              let in_ch = open_in filename in
              let map =
                (try
                   read_and_split MapString.empty in_ch
                 with e -> close_in in_ch; raise e)
              in
              close_in in_ch;
              map
            with exn ->
                    Lwt_log.ign_error ~section ~exn
               "unable to read the mime.types file";
                   MapString.empty
           )];
    assoc_default = default_mime_type;
  }


let default_mime_assoc () =
  let parsed = ref None in
  match !parsed with
    | None ->
        let filename = !Ocsigen_config_static.mimefile in
        Lwt_log.ign_info_f ~section "Loading mime types in '%s'" filename;
        let map = parse_mime_types ~filename in
        parsed := Some map;
        map
    | Some map -> map
OCaml

Innovation. Community. Security.