| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <title>JSDoc: Source: odata/batch.js</title> |
| |
| <script src="scripts/prettify/prettify.js"> </script> |
| <script src="scripts/prettify/lang-css.js"> </script> |
| <!--[if lt IE 9]> |
| <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> |
| <![endif]--> |
| <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> |
| <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> |
| </head> |
| |
| <body> |
| |
| <div id="main"> |
| |
| <h1 class="page-title">Source: odata/batch.js</h1> |
| |
| |
| |
| |
| |
| <section> |
| <article> |
| <pre class="prettyprint source"><code>/*
|
| * Licensed to the Apache Software Foundation (ASF) under one
|
| * or more contributor license agreements. See the NOTICE file
|
| * distributed with this work for additional information
|
| * regarding copyright ownership. The ASF licenses this file
|
| * to you under the Apache License, Version 2.0 (the
|
| * "License"); you may not use this file except in compliance
|
| * with the License. You may obtain a copy of the License at
|
| *
|
| * http://www.apache.org/licenses/LICENSE-2.0
|
| *
|
| * Unless required by applicable law or agreed to in writing,
|
| * software distributed under the License is distributed on an
|
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
| * KIND, either express or implied. See the License for the
|
| * specific language governing permissions and limitations
|
| * under the License.
|
| */
|
| 'use strict';
|
|
|
| /** @module odata/batch */
|
|
|
| var utils = require('./../utils.js');
|
| var odataUtils = require('./odatautils.js');
|
| var odataHandler = require('./handler.js');
|
|
|
| var extend = utils.extend;
|
| var isArray = utils.isArray;
|
| var trimString = utils.trimString;
|
|
|
| var contentType = odataHandler.contentType;
|
| var handler = odataHandler.handler;
|
| var isBatch = odataUtils.isBatch;
|
| var MAX_DATA_SERVICE_VERSION = odataHandler.MAX_DATA_SERVICE_VERSION;
|
| var normalizeHeaders = odataUtils.normalizeHeaders;
|
| //TODO var payloadTypeOf = odata.payloadTypeOf;
|
| var prepareRequest = odataUtils.prepareRequest;
|
|
|
|
|
| // Imports
|
|
|
| // CONTENT START
|
| var batchMediaType = "multipart/mixed";
|
| var responseStatusRegex = /^HTTP\/1\.\d (\d{3}) (.*)$/i;
|
| var responseHeaderRegex = /^([^()<>@,;:\\"\/[\]?={} \t]+)\s?:\s?(.*)/;
|
|
|
| /** Calculates a random 16 bit number and returns it in hexadecimal format.
|
| * @returns {String} A 16-bit number in hex format.
|
| */
|
| function hex16() {
|
|
|
| return Math.floor((1 + Math.random()) * 0x10000).toString(16).substr(1);
|
| }
|
|
|
| /** Creates a string that can be used as a multipart request boundary.
|
| * @param {String} [prefix] -
|
| * @returns {String} Boundary string of the format: <prefix><hex16>-<hex16>-<hex16>
|
| */
|
| function createBoundary(prefix) {
|
|
|
| return prefix + hex16() + "-" + hex16() + "-" + hex16();
|
| }
|
|
|
| /** Gets the handler for data serialization of individual requests / responses in a batch.
|
| * @param context - Context used for data serialization.
|
| * @returns Handler object
|
| */
|
| function partHandler(context) {
|
|
|
| return context.handler.partHandler;
|
| }
|
|
|
| /** Gets the current boundary used for parsing the body of a multipart response.
|
| * @param context - Context used for parsing a multipart response.
|
| * @returns {String} Boundary string.
|
| */
|
| function currentBoundary(context) {
|
| var boundaries = context.boundaries;
|
| return boundaries[boundaries.length - 1];
|
| }
|
|
|
| /** Parses a batch response.
|
| * @param handler - This handler.
|
| * @param {String} text - Batch text.
|
| * @param {Object} context - Object with parsing context.
|
| * @return An object representation of the batch.
|
| */
|
| function batchParser(handler, text, context) {
|
|
|
| var boundary = context.contentType.properties["boundary"];
|
| return { __batchResponses: readBatch(text, { boundaries: [boundary], handlerContext: context }) };
|
| }
|
|
|
| /** Serializes a batch object representation into text.
|
| * @param handler - This handler.
|
| * @param {Object} data - Representation of a batch.
|
| * @param {Object} context - Object with parsing context.
|
| * @return An text representation of the batch object; undefined if not applicable.#
|
| */
|
| function batchSerializer(handler, data, context) {
|
|
|
| var cType = context.contentType = context.contentType || contentType(batchMediaType);
|
| if (cType.mediaType === batchMediaType) {
|
| return writeBatch(data, context);
|
| }
|
| }
|
|
|
| /** Parses a multipart/mixed response body from from the position defined by the context.
|
| * @param {String} text - Body of the multipart/mixed response.
|
| * @param context - Context used for parsing.
|
| * @return Array of objects representing the individual responses.
|
| */
|
| function readBatch(text, context) {
|
| var delimiter = "--" + currentBoundary(context);
|
|
|
| // Move beyond the delimiter and read the complete batch
|
| readTo(text, context, delimiter);
|
|
|
| // Ignore the incoming line
|
| readLine(text, context);
|
|
|
| // Read the batch parts
|
| var responses = [];
|
| var partEnd = null;
|
|
|
| while (partEnd !== "--" && context.position < text.length) {
|
| var partHeaders = readHeaders(text, context);
|
| var partContentType = contentType(partHeaders["Content-Type"]);
|
|
|
| var changeResponses;
|
| if (partContentType && partContentType.mediaType === batchMediaType) {
|
| context.boundaries.push(partContentType.properties.boundary);
|
| try {
|
| changeResponses = readBatch(text, context);
|
| } catch (e) {
|
| e.response = readResponse(text, context, delimiter);
|
| changeResponses = [e];
|
| }
|
| responses.push({ __changeResponses: changeResponses });
|
| context.boundaries.pop();
|
| readTo(text, context, "--" + currentBoundary(context));
|
| } else {
|
| if (!partContentType || partContentType.mediaType !== "application/http") {
|
| throw { message: "invalid MIME part type " };
|
| }
|
| // Skip empty line
|
| readLine(text, context);
|
| // Read the response
|
| var response = readResponse(text, context, delimiter);
|
| try {
|
| if (response.statusCode >= 200 && response.statusCode <= 299) {
|
| partHandler(context.handlerContext).read(response, context.handlerContext);
|
| } else {
|
| // Keep track of failed responses and continue processing the batch.
|
| response = { message: "HTTP request failed", response: response };
|
| }
|
| } catch (e) {
|
| response = e;
|
| }
|
|
|
| responses.push(response);
|
| }
|
|
|
| partEnd = text.substr(context.position, 2);
|
|
|
| // Ignore the incoming line.
|
| readLine(text, context);
|
| }
|
| return responses;
|
| }
|
|
|
| /** Parses the http headers in the text from the position defined by the context.
|
| * @param {String} text - Text containing an http response's headers
|
| * @param context - Context used for parsing.
|
| * @returns Object containing the headers as key value pairs.
|
| * This function doesn't support split headers and it will stop reading when it hits two consecutive line breaks.
|
| */
|
| function readHeaders(text, context) {
|
| var headers = {};
|
| var parts;
|
| var line;
|
| var pos;
|
|
|
| do {
|
| pos = context.position;
|
| line = readLine(text, context);
|
| parts = responseHeaderRegex.exec(line);
|
| if (parts !== null) {
|
| headers[parts[1]] = parts[2];
|
| } else {
|
| // Whatever was found is not a header, so reset the context position.
|
| context.position = pos;
|
| }
|
| } while (line && parts);
|
|
|
| normalizeHeaders(headers);
|
|
|
| return headers;
|
| }
|
|
|
| /** Parses an HTTP response.
|
| * @param {String} text -Text representing the http response.
|
| * @param context optional - Context used for parsing.
|
| * @param {String} delimiter -String used as delimiter of the multipart response parts.
|
| * @return Object representing the http response.
|
| */
|
| function readResponse(text, context, delimiter) {
|
| // Read the status line.
|
| var pos = context.position;
|
| var match = responseStatusRegex.exec(readLine(text, context));
|
|
|
| var statusCode;
|
| var statusText;
|
| var headers;
|
|
|
| if (match) {
|
| statusCode = match[1];
|
| statusText = match[2];
|
| headers = readHeaders(text, context);
|
| readLine(text, context);
|
| } else {
|
| context.position = pos;
|
| }
|
|
|
| return {
|
| statusCode: statusCode,
|
| statusText: statusText,
|
| headers: headers,
|
| body: readTo(text, context, "\r\n" + delimiter)
|
| };
|
| }
|
|
|
| /** Returns a substring from the position defined by the context up to the next line break (CRLF).
|
| * @param {String} text - Input string.
|
| * @param context - Context used for reading the input string.
|
| * @returns {String} Substring to the first ocurrence of a line break or null if none can be found.
|
| */
|
| function readLine(text, context) {
|
|
|
| return readTo(text, context, "\r\n");
|
| }
|
|
|
| /** Returns a substring from the position given by the context up to value defined by the str parameter and increments the position in the context.
|
| * @param {String} text - Input string.
|
| * @param context - Context used for reading the input string.
|
| * @param {String} [str] - Substring to read up to.
|
| * @returns {String} Substring to the first ocurrence of str or the end of the input string if str is not specified. Null if the marker is not found.
|
| */
|
| function readTo(text, context, str) {
|
| var start = context.position || 0;
|
| var end = text.length;
|
| if (str) {
|
| end = text.indexOf(str, start);
|
| if (end === -1) {
|
| return null;
|
| }
|
| context.position = end + str.length;
|
| } else {
|
| context.position = end;
|
| }
|
|
|
| return text.substring(start, end);
|
| }
|
|
|
| /** Serializes a batch request object to a string.
|
| * @param data - Batch request object in payload representation format
|
| * @param context - Context used for the serialization
|
| * @returns {String} String representing the batch request
|
| */
|
| function writeBatch(data, context) {
|
| if (!isBatch(data)) {
|
| throw { message: "Data is not a batch object." };
|
| }
|
|
|
| var batchBoundary = createBoundary("batch_");
|
| var batchParts = data.__batchRequests;
|
| var batch = "";
|
| var i, len;
|
| for (i = 0, len = batchParts.length; i < len; i++) {
|
| batch += writeBatchPartDelimiter(batchBoundary, false) +
|
| writeBatchPart(batchParts[i], context);
|
| }
|
| batch += writeBatchPartDelimiter(batchBoundary, true);
|
|
|
| // Register the boundary with the request content type.
|
| var contentTypeProperties = context.contentType.properties;
|
| contentTypeProperties.boundary = batchBoundary;
|
|
|
| return batch;
|
| }
|
|
|
| /** Creates the delimiter that indicates that start or end of an individual request.
|
| * @param {String} boundary Boundary string used to indicate the start of the request
|
| * @param {Boolean} close - Flag indicating that a close delimiter string should be generated
|
| * @returns {String} Delimiter string
|
| */
|
| function writeBatchPartDelimiter(boundary, close) {
|
| var result = "\r\n--" + boundary;
|
| if (close) {
|
| result += "--";
|
| }
|
|
|
| return result + "\r\n";
|
| }
|
|
|
| /** Serializes a part of a batch request to a string. A part can be either a GET request or
|
| * a change set grouping several CUD (create, update, delete) requests.
|
| * @param part - Request or change set object in payload representation format
|
| * @param context - Object containing context information used for the serialization
|
| * @param {boolean} [nested] -
|
| * @returns {String} String representing the serialized part
|
| * A change set is an array of request objects and they cannot be nested inside other change sets.
|
| */
|
| function writeBatchPart(part, context, nested) {
|
|
|
|
|
| var changeSet = part.__changeRequests;
|
| var result;
|
| if (isArray(changeSet)) {
|
| if (nested) {
|
| throw { message: "Not Supported: change set nested in other change set" };
|
| }
|
|
|
| var changeSetBoundary = createBoundary("changeset_");
|
| result = "Content-Type: " + batchMediaType + "; boundary=" + changeSetBoundary + "\r\n";
|
| var i, len;
|
| for (i = 0, len = changeSet.length; i < len; i++) {
|
| result += writeBatchPartDelimiter(changeSetBoundary, false) +
|
| writeBatchPart(changeSet[i], context, true);
|
| }
|
|
|
| result += writeBatchPartDelimiter(changeSetBoundary, true);
|
| } else {
|
| result = "Content-Type: application/http\r\nContent-Transfer-Encoding: binary\r\n\r\n";
|
| var partContext = extend({}, context);
|
| partContext.handler = handler;
|
| partContext.request = part;
|
| partContext.contentType = null;
|
|
|
| prepareRequest(part, partHandler(context), partContext);
|
| result += writeRequest(part);
|
| }
|
|
|
| return result;
|
| }
|
|
|
| /** Serializes a request object to a string.
|
| * @param request - Request object to serialize
|
| * @returns {String} String representing the serialized request
|
| */
|
| function writeRequest(request) {
|
| var result = (request.method ? request.method : "GET") + " " + request.requestUri + " HTTP/1.1\r\n";
|
| for (var name in request.headers) {
|
| if (request.headers[name]) {
|
| result = result + name + ": " + request.headers[name] + "\r\n";
|
| }
|
| }
|
|
|
| result += "\r\n";
|
|
|
| if (request.body) {
|
| result += request.body;
|
| }
|
|
|
| return result;
|
| }
|
|
|
|
|
|
|
| /** batchHandler (see {@link module:odata/batch~batchParser}) */
|
| exports.batchHandler = handler(batchParser, batchSerializer, batchMediaType, MAX_DATA_SERVICE_VERSION);
|
|
|
| /** batchSerializer (see {@link module:odata/batch~batchSerializer}) */
|
| exports.batchSerializer = batchSerializer;
|
|
|
| /** writeRequest (see {@link module:odata/batch~writeRequest}) */
|
| exports.writeRequest = writeRequest;</code></pre> |
| </article> |
| </section> |
| |
| |
| |
| |
| </div> |
| |
| <nav> |
| <h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="module-cache.html">cache</a></li><li><a href="source.html">cache/source</a></li><li><a href="module-odata.html">odata</a></li><li><a href="batch.html">odata/batch</a></li><li><a href="handler.html">odata/handler</a></li><li><a href="json.html">odata/json</a></li><li><a href="metadata.html">odata/metadata</a></li><li><a href="net.html">odata/net</a></li><li><a href="utils.html">odata/utils</a></li><li><a href="deferred.html">odatajs/deferred</a></li><li><a href="utils_.html">odatajs/utils</a></li><li><a href="xml.html">odatajs/xml</a></li><li><a href="module-store.html">store</a></li><li><a href="dom.html">store/dom</a></li><li><a href="indexeddb.html">store/indexeddb</a></li><li><a href="memory.html">store/memory</a></li></ul><h3>Classes</h3><ul><li><a href="DataCache.html">DataCache</a></li><li><a href="DataCacheOperation.html">DataCacheOperation</a></li><li><a href="DjsDeferred.html">DjsDeferred</a></li><li><a href="dom-DomStore.html">DomStore</a></li><li><a href="indexeddb-IndexedDBStore.html">IndexedDBStore</a></li><li><a href="memory-MemoryStore.html">MemoryStore</a></li><li><a href="ODataCacheSource.html">ODataCacheSource</a></li></ul><h3><a href="global.html">Global</a></h3> |
| </nav> |
| |
| <br clear="both"> |
| |
| <footer> |
| Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Thu Apr 09 2015 08:31:26 GMT+0200 (MESZ) |
| </footer> |
| |
| <script> prettyPrint(); </script> |
| <script src="scripts/linenumber.js"> </script> |
| </body> |
| </html> |