Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | const Cc = Components.classes; |
michael@0 | 2 | const Ci = Components.interfaces; |
michael@0 | 3 | const CC = Components.Constructor; |
michael@0 | 4 | |
michael@0 | 5 | const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1", |
michael@0 | 6 | "nsIBinaryInputStream", |
michael@0 | 7 | "setInputStream"); |
michael@0 | 8 | |
michael@0 | 9 | function parseHeaders(data, start) |
michael@0 | 10 | { |
michael@0 | 11 | let headers = {}; |
michael@0 | 12 | |
michael@0 | 13 | while (true) { |
michael@0 | 14 | let done = false; |
michael@0 | 15 | let end = data.indexOf("\r\n", start); |
michael@0 | 16 | if (end == -1) { |
michael@0 | 17 | done = true; |
michael@0 | 18 | end = data.length; |
michael@0 | 19 | } |
michael@0 | 20 | let line = data.substring(start, end); |
michael@0 | 21 | start = end + 2; |
michael@0 | 22 | if (line == "") |
michael@0 | 23 | // empty line, we're done |
michael@0 | 24 | break; |
michael@0 | 25 | |
michael@0 | 26 | //XXX: this doesn't handle multi-line headers. do we care? |
michael@0 | 27 | let [name, value] = line.split(':'); |
michael@0 | 28 | //XXX: not normalized, should probably use nsHttpHeaders or something |
michael@0 | 29 | headers[name] = value.trimLeft(); |
michael@0 | 30 | } |
michael@0 | 31 | return [headers, start]; |
michael@0 | 32 | } |
michael@0 | 33 | |
michael@0 | 34 | function parseMultipartForm(request) |
michael@0 | 35 | { |
michael@0 | 36 | let boundary = null; |
michael@0 | 37 | // See if this is a multipart/form-data request, and if so, find the |
michael@0 | 38 | // boundary string |
michael@0 | 39 | if (request.hasHeader("Content-Type")) { |
michael@0 | 40 | var contenttype = request.getHeader("Content-Type"); |
michael@0 | 41 | var bits = contenttype.split(";"); |
michael@0 | 42 | if (bits[0] == "multipart/form-data") { |
michael@0 | 43 | for (var i = 1; i < bits.length; i++) { |
michael@0 | 44 | var b = bits[i].trimLeft(); |
michael@0 | 45 | if (b.indexOf("boundary=") == 0) { |
michael@0 | 46 | // grab everything after boundary= |
michael@0 | 47 | boundary = "--" + b.substring(9); |
michael@0 | 48 | break; |
michael@0 | 49 | } |
michael@0 | 50 | } |
michael@0 | 51 | } |
michael@0 | 52 | } |
michael@0 | 53 | if (boundary == null) |
michael@0 | 54 | return null; |
michael@0 | 55 | |
michael@0 | 56 | let body = new BinaryInputStream(request.bodyInputStream); |
michael@0 | 57 | let avail; |
michael@0 | 58 | let bytes = []; |
michael@0 | 59 | while ((avail = body.available()) > 0) { |
michael@0 | 60 | let readBytes = body.readByteArray(avail); |
michael@0 | 61 | for (let b of readBytes) { |
michael@0 | 62 | bytes.push(b); |
michael@0 | 63 | } |
michael@0 | 64 | } |
michael@0 | 65 | let data = ""; |
michael@0 | 66 | for (let b of bytes) { |
michael@0 | 67 | data += String.fromCharCode(b); |
michael@0 | 68 | } |
michael@0 | 69 | let formData = {}; |
michael@0 | 70 | let done = false; |
michael@0 | 71 | let start = 0; |
michael@0 | 72 | while (true) { |
michael@0 | 73 | // read first line |
michael@0 | 74 | let end = data.indexOf("\r\n", start); |
michael@0 | 75 | if (end == -1) { |
michael@0 | 76 | done = true; |
michael@0 | 77 | end = data.length; |
michael@0 | 78 | } |
michael@0 | 79 | |
michael@0 | 80 | let line = data.substring(start, end); |
michael@0 | 81 | // look for closing boundary delimiter line |
michael@0 | 82 | if (line == boundary + "--") { |
michael@0 | 83 | break; |
michael@0 | 84 | } |
michael@0 | 85 | |
michael@0 | 86 | if (line != boundary) { |
michael@0 | 87 | dump("expected boundary line but didn't find it!"); |
michael@0 | 88 | break; |
michael@0 | 89 | } |
michael@0 | 90 | |
michael@0 | 91 | // parse headers |
michael@0 | 92 | start = end + 2; |
michael@0 | 93 | let headers = null; |
michael@0 | 94 | [headers, start] = parseHeaders(data, start); |
michael@0 | 95 | |
michael@0 | 96 | // find next boundary string |
michael@0 | 97 | end = data.indexOf("\r\n" + boundary, start); |
michael@0 | 98 | if (end == -1) { |
michael@0 | 99 | dump("couldn't find next boundary string\n"); |
michael@0 | 100 | break; |
michael@0 | 101 | } |
michael@0 | 102 | |
michael@0 | 103 | // read part data, stick in formData using Content-Disposition header |
michael@0 | 104 | let part = data.substring(start, end); |
michael@0 | 105 | start = end + 2; |
michael@0 | 106 | |
michael@0 | 107 | if ("Content-Disposition" in headers) { |
michael@0 | 108 | let bits = headers["Content-Disposition"].split(';'); |
michael@0 | 109 | if (bits[0] == 'form-data') { |
michael@0 | 110 | for (let i = 0; i < bits.length; i++) { |
michael@0 | 111 | let b = bits[i].trimLeft(); |
michael@0 | 112 | if (b.indexOf('name=') == 0) { |
michael@0 | 113 | //TODO: handle non-ascii here? |
michael@0 | 114 | let name = b.substring(6, b.length - 1); |
michael@0 | 115 | //TODO: handle multiple-value properties? |
michael@0 | 116 | formData[name] = part; |
michael@0 | 117 | } |
michael@0 | 118 | //TODO: handle filename= ? |
michael@0 | 119 | //TODO: handle multipart/mixed for multi-file uploads? |
michael@0 | 120 | } |
michael@0 | 121 | } |
michael@0 | 122 | } |
michael@0 | 123 | } |
michael@0 | 124 | return formData; |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | function handleRequest(request, response) |
michael@0 | 128 | { |
michael@0 | 129 | if (request.method == "GET") { |
michael@0 | 130 | let id = null; |
michael@0 | 131 | for each(p in request.queryString.split('&')) { |
michael@0 | 132 | let [key, value] = p.split('='); |
michael@0 | 133 | if (key == 'id') |
michael@0 | 134 | id = value; |
michael@0 | 135 | } |
michael@0 | 136 | if (id == null) { |
michael@0 | 137 | response.setStatusLine(request.httpVersion, 400, "Bad Request"); |
michael@0 | 138 | response.write("Missing id parameter"); |
michael@0 | 139 | } |
michael@0 | 140 | else { |
michael@0 | 141 | let data = getState(id); |
michael@0 | 142 | if (data == "") { |
michael@0 | 143 | response.setStatusLine(request.httpVersion, 404, "Not Found"); |
michael@0 | 144 | response.write("Not Found"); |
michael@0 | 145 | } |
michael@0 | 146 | else { |
michael@0 | 147 | response.setHeader("Content-Type", "text/plain", false); |
michael@0 | 148 | response.write(data); |
michael@0 | 149 | } |
michael@0 | 150 | } |
michael@0 | 151 | } |
michael@0 | 152 | else if (request.method == "POST") { |
michael@0 | 153 | let formData = parseMultipartForm(request); |
michael@0 | 154 | |
michael@0 | 155 | if (formData && 'upload_file_minidump' in formData) { |
michael@0 | 156 | response.setHeader("Content-Type", "text/plain", false); |
michael@0 | 157 | |
michael@0 | 158 | let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"] |
michael@0 | 159 | .getService(Ci.nsIUUIDGenerator); |
michael@0 | 160 | let uuid = uuidGenerator.generateUUID().toString(); |
michael@0 | 161 | // ditch the {}, add bp- prefix |
michael@0 | 162 | uuid = 'bp-' + uuid.substring(1,uuid.length-2); |
michael@0 | 163 | |
michael@0 | 164 | let d = JSON.stringify(formData); |
michael@0 | 165 | //dump('saving crash report ' + uuid + ': ' + d + '\n'); |
michael@0 | 166 | setState(uuid, d); |
michael@0 | 167 | |
michael@0 | 168 | response.write("CrashID=" + uuid + "\n"); |
michael@0 | 169 | } |
michael@0 | 170 | else { |
michael@0 | 171 | dump('*** crashreport.sjs: Malformed request?\n'); |
michael@0 | 172 | response.setStatusLine(request.httpVersion, 400, "Bad Request"); |
michael@0 | 173 | response.write("Missing minidump file"); |
michael@0 | 174 | } |
michael@0 | 175 | } |
michael@0 | 176 | else { |
michael@0 | 177 | response.setStatusLine(request.httpVersion, 405, "Method not allowed"); |
michael@0 | 178 | response.write("Can't handle HTTP method " + request.method); |
michael@0 | 179 | } |
michael@0 | 180 | } |