www.gusucode.com > external 工具箱matlab源码程序 > external/interfaces/webservices/http/+matlab/+net/+http/Message.m

    classdef (Abstract, AllowedSubclasses={?matlab.net.http.RequestMessage, ...
                                       ?matlab.net.http.ResponseMessage}) Message < ...
                                       matlab.mixin.Heterogeneous
% Message Abstract base class of HTTP messages
%
%   Message properties:
%
%     StartLine - the start line
%     Header    - header of the message
%     Body      - body of the message
%     Completed - true if message is completed
%
%   Message methods:
%
%     getFields    - return header fields
%     addFields    - add header fields
%     changeFields - change existing header fields
%     removeFields - remove header fields
%     string       - return the contents of the message as a string
%     char         - return the contents of the message as a character vector
%     show         - return the message as a string with optional maximum length
%
% See also matlab.net.http.RequestMessage, matlab.net.http.ResponseMessage

% Copyright 2015-2016 The MathWorks, Inc.    

    properties
        % StartLine - start line of the message, a matlab.net.http.StartLine
        StartLine % It's really a matlab.net.http.StartLine but we can't declare an abstract type w/o initializing it
        % Header - header of the message, vector of matlab.net.http.HeaderField
        %   When you set this property, the fields of the Header will be checked to
        %   insure that they are appropriate for the type of message.  
        %
        % See also HeaderField
        Header matlab.net.http.HeaderField
        % Body - body of the message, a matlab.net.http.MessageBody
        %   You may set this property to a MessageBody or any value acceptable to the
        %   MessageBody constructor.  If this message has a Content-Type header field,
        %   Body.ContentType will be set to the MediaType of that field, overriding
        %   any previous value that might be set in that property.  Otherwise it will
        %   be unchanged.
        %
        % See also MessageBody, matlab.net.http.field.ContentTypeField
        Body matlab.net.http.MessageBody
    end
    
    properties (Transient)
        % Completed - true if this message was completed
        %   This property means that the message contains all the headers sent or
        %   received, and if there is a payload, the raw payload as well as possibly
        %   converted data in Body.
        %
        %   In a RequestMessage, methods that validate this message, such as
        %   RequestMessage.send and RequestMessage.complete, set this property to true
        %   once determining that the message is valid and completing any processing
        %   such as adding required header fields and converting Body.Data to
        %   Body.Paylod.  If you set this to true prior to issuing send or complete,
        %   these methods will not modify message headers, and the send method will
        %   send the message without checking it for validity.  Any change to a
        %   property in a message resets this property back to false.
        %
        %   In a ResponseMessage, this property is true if the message contains no
        %   payload (Body or Body.Data are empty), or if Body.Payload contains the raw
        %   data.  
        %
        %   Set this to true in a RequestMessage if you want to prevent the send
        %   method from modifying the headers of the message, thereby letting you send
        %   arbitrary headers.  You can still use the complete method to
        %   validate the message, but the send method will attempt to send it whether
        %   or not it is valid.  Even if Completed is set, the send method will fill
        %   in any properties of the RequestLine that are empty, and may convert
        %   Body.Data, but it will not reject the message due to invalid headers.
        %
        %   If Body.Payload contains data and Completed is true, RequestMessage.send
        %   will send the payload as is, without attempting to convert any information
        %   in Body.Data.  But if Body.Data is nonempty and Body.Payload is empty,
        %   RequestMessage.send will always convert the data based on the content type
        %   (obtained from the Content-Type header field or derived from the type of
        %   Data), regardless of the value of Completed, as it needs to do so to send
        %   the message.
        %
        %   The Completed property set in a RequestMessage or ResponseMessage returned
        %   by RequestMessage.send, or in the HISTORY returned by send, indicates that
        %   the message contains exactly what was sent to or received from the server.
        %   For messages containing a body, this includes the raw data in
        %   Body.Payload.  This raw data is not preserved in ReponseMessages unless
        %   you set HTTPOptions.SavePayload or there was an error trying to convert the
        %   payload, so ResponseMessages with a body will not normally have Completed
        %   set.
        %
        % See also matlab.net.http.RequestMessage.send,
        % matlab.net.http.RequestMessage.complete, Body, MessageBody,
        % matlab.net.http.HTTPOptions.SavePayload, ResponseMessage
        Completed logical = false
    end
    
    methods
        function obj = set.Header(obj, value)
            if ~isempty(value) 
                validateattributes(value, {'matlab.net.http.HeaderField'}, ...
                                   {'vector'}, mfilename, 'Header');
                badField = obj.getInvalidFields(value);
                if isempty(badField)
                    obj.Header = value;
                else
                    if isempty(badField.Value)
                        error(message('MATLAB:http:BadFieldNameInHeader', ...
                            char(badField.Name), class(obj)));
                    else
                        error(message('MATLAB:http:BadFieldValueInHeader', ...
                            char(badField.Name), char(badField.Value), class(obj)));
                    end
                end
                obj.checkHeader(value);
            end
            obj.Header = value;
            obj.Completed = false; %#ok<MCSUP> because Completed transient
            if obj.shouldSetBodyContentType()
                % copy the ContentType header field into the body, if there is one
                ct = obj.getBodyContentType();
                if ~isempty(ct)
                    % note this does not call the set.Body method
                    obj.Body.ContentType = ct; %#ok<MCSUP> because ContentType transient
                end
            end
        end
        
        function obj = set.Body(obj, value)
            obj.checkBody(value);
            if isa(value, 'matlab.net.http.MessageBody')
                obj.Body = value;
            else
                obj.Body = matlab.net.http.MessageBody(value);
            end
            if obj.shouldSetBodyContentType()
                % copy the ContentType header field into the body, if there is one
                ct = obj.getBodyContentType();
                if ~isempty(ct)
                    obj.Body.ContentType = ct;
                end
            end
            obj.Completed = false; %#ok<MCSUP> because Completed transient
        end
        
        function obj = set.StartLine(obj, value)
            if ~isempty(value) || ~isnumeric(value)
                validateattributes(value, {obj.getStartLineType() ...
                                    'matlab.net.http.StartLine'}, {'scalar'}, mfilename, 'StartLine');
            end
            obj.StartLine = value;
            obj.Completed = false; %#ok<MCSUP> because Completed transient
        end
        
        function obj = set.Completed(obj, value)
            validateattributes(value, {'logical'}, {'scalar'}, mfilename, 'Completed');
            obj.Completed = value;
        end
    end
    
    methods (Sealed)
        % These methods are sealed so they can be called on a heterogeneous array
        
        function [fields, indices] = getFields(obj, varargin)
        % getFields Return fields from HTTP message headers
        %   [FIELDS, INDICES] = getFields(MESSAGES, IDS) returns FIELDS, a vector of
        %     HeaderField in the vector of MESSAGES that match the IDS, and a vector
        %     of their INDICES. The IDS can be:
        %       - a character vector, vector of strings, comma-separated list of
        %         strings or character vectors, or cell array of character vectors
        %         naming the fields to be returned.  Names are not case-sensitive.
        %       - a vector of HeaderField or comma separated list of them, whose names 
        %         are used to determine which fields to return.  Names are not
        %         case-sensitive and Values of the HeaderFields are ignored.
        %       - a vector of meta.class that are subclasses of HeaderField, or 
        %         comma-separated list of them.  For each class, this matches any
        %         fields that are instances of that class (including its subclasses)
        %         plus any fields whose names match the names explicitly supported by
        %         the class or its subclasses.
        %
        %         For example MediaRangeField has two subclasses, AcceptField and
        %         ContentTypeField.  If you specify an ID of
        %         ?matlab.net.http.field.MediaRangeField it will match all fields of
        %         of class MediaRangeField, AcceptField and ContentTypeField, plus any
        %         fields with the Name 'Accept' or 'Content-Type' (such as
        %         matlab.net.http.HeaderField or matlab.net.http.field.GenericField).
        %
        %     If MESSAGES contains more then one message, INDICES is a cell array of
        %     vectors, where INDICES{i} contains the indices of the matching fields
        %     in MESSAGE(i).
        %
        %     If there is no match, Fields is HeaderField.empty.
        %
        %     Header field name matching is case-insensitive.
        %
        %     If there is more than one match, FIELDS is a vector containing all the
        %     matches.  If they are all the same type, it is generally possible to
        %     call convert(FIELDS) to obtain a vector of their converted values.
        %     Except for the Set-Cookie field, multiple fields of the same type are
        %     allowed in a message only if the field syntax supports a comma-separated
        %     list of values.
        %
        % See also HeaderField, removeFields, addFields, changeFields, meta.class,
        % matlab.net.http.HeaderField.convert, matlab.net.http.field.SetCookieField,
        % matlab.net.http.field.MediaRangeField, matlab.net.http.field.AcceptField,
        % matlab.net.http.field.ContentTypeField
            fields = matlab.net.http.HeaderField.empty;
            if isempty(varargin)
                error(message('MATLAB:minrhs'));
            end
            if nargout > 1
                if ~isscalar(obj)
                    indices{length(obj)} = [];
                else
                    indices = [];
                end
            end
            % look for HeaderField instances
            ids = getFieldsVector(varargin);
            if isempty(ids)
                % none; look for mata.class instances
                ids = getFieldsVector(varargin,'meta.class');
                if isempty(ids) 
                    ids = getNameVector(varargin);
                end
            end
            names = getMatchingNames(ids);
            if isa(ids, 'meta.class')
                classes = ids;
            else
                classes = [];
            end
            for i = 1 : length(obj)
                msg = obj(i);
                idx = [];
                if ~isempty(msg.Header)
                    hdrNames = [msg.Header.Name];
                    matches = zeros(1,length(hdrNames));
                    % first match the names
                    for j = 1 : length(names)
                        matches = matches | strcmpi(names(j), hdrNames);
                    end
                    if ~isempty(classes)
                        % next match the classes, if any
                        matches = matches | ...
                            arrayfun(@(hdr) any(metaclass(hdr) <= classes), msg.Header); 
                    end
                    if isempty(fields)
                        fields = msg.Header(matches);
                    else
                        fields = [fields msg.Header(matches)]; %#ok<AGROW>
                    end
                    if nargout > 1
                        idx = find(matches);
                    end
                end 
                if nargout > 1
                    if iscell(indices)
                        indices{i} = idx;
                    else
                        indices = idx;
                    end
                end
            end
            if isempty(fields)
                % g1393498 workaround
                fields = matlab.net.http.HeaderField.empty;
            end
        end
        
        function obj = addFields(obj, varargin)
        % addFields Add fields to an HTTP message header
        %   MSG = addFields(MSG,FIELDS) returns a copy of the message array MSG with
        %     additional fields added to the end of the header of each message.
        %     FIELDS is a vector of HeaderField objects or comma separated list of
        %     them.  There is no check for duplicate fields, but RequestMessage.send
        %     and RequestMessage.complete may reject inappropriate duplicates.
        %
        %   MSG = addFields(MSG,NAME1,VALUE1,...,NAMEn,VALUEn) adds fields with NAME 
        %     and VALUE to end of Header.  A VALUE may be '' to use the default value
        %     for the field (usually, but not necessarily, []).  If the last VALUE
        %     is missing, it is the same as specifying [] (see below). The type of
        %     HeaderField object created depends on its NAME, and any VALUEs are
        %     validated for that type.
        %
        %   MSG = addFields(MSG,INDEX,___) inserts fields at the specified INDEX in 
        %     Header.  Can be used in combination with any of above.  Adds to end if
        %     INDEX is greater than length of Header.  If INDEX is negative, counts
        %     from end of header, where 0 adds fields to the end and -1 inserts
        %     fields before the last field.
        %
        %   If the value of any header field is [], this indicates that the field
        %   should not be automatically added when the message is sent or completed.
        %   In a message already completed, a value of [] does not remove instances
        %   of that field already present in the message.  Fields with empty values
        %   are remvoed from the message prior to sending.
        %
        % See also HeaderField, RequestMessage, getFields, changeFields,
        % removeFields, Completed, complete
        
        % Undocumented behavior for internal use only -- this may change in a future
        % release:
        %   addFields(STRUCTS) - array of structures containing Name and Value
        %     fields.
            obj = obj.addFieldsPrivate(true, varargin{:});
            matlab.net.http.internal.nargoutWarning(nargout,mfilename,'addFields');
        end
        
        function obj = changeFields(obj, varargin)
        % changeFields Change existing fields in an HTTP message header
        %   MSG = changeFields(MSG,NAME1,VALUE1,...,NAMEn,VALUEn) returns a copy of
        %     the message array MSG with changes to the values of existing fields in
        %     each message.  NAME is the name of the field and VALUE is the new value.
        %     Specify a VALUE of '' to reset a field to its default value, or [] to
        %     prevent the field from being automatically added when the message is
        %     completed (e.g., by RequestMessage.send or RequestMessaget.complete).
        %     The last VALUE, if missing, is assumed to be [].
        %
        %     NAME matching is case-insensitive; however if the NAME you specify
        %     differs in case from the existing name, then the field's name will be
        %     changed to NAME.  This usage will never change the class of an existing
        %     field in MSG.
        %     
        %   MSG = changeFields(MSG,FIELDS) changes existing fields to the names,
        %     values and types in FIELDS, a vector of HeaderFields or comma-separated
        %     list of them.  This may change the class of an existing field if it has
        %     a case-insensitive match to a name in FIELDS.
        %
        %  This function throws an error if all the specified fields are not already
        %  in the header of each message, or if there is more than one match to a
        %  specified field.
        %
        % See also HeaderField, addFields, getFields, removeFields
        % matlab.net.http.RequestMessage.send, matlab.net.http.RequestMessage.complete

            % Make array of generic HeaderField objects out of args and validate proposed
            % values.
            fields = getFieldsVector(varargin);
            if ~isempty(fields)
                useClasses = true;
            else
                useClasses = false;
                names = varargin(1:2:end);
                values = varargin(2:2:end);
                if length(values) < length(names) 
                    values{end+1} = []; % append empty to end if not enough values
                end
                % Call the HeaderField constructors on each.  This will validate that the
                % values are valid for those names.
                fields = cellfun(@(n,v)matlab.net.http.HeaderField(n,v), ...
                             names, values, 'UniformOutput', false);
                fields = [fields{:}];  % take HeaderFields out of their cells
            end
            for midx = 1 : length(obj)
                msg = obj(midx);
                msg.checkHeader(fields);  % validate fields are appropriate
                % Now merge them in. 
                for i = 1 : length(fields)
                    name = fields(i).Name;
                    % match is vector of matching fields
                    if isempty(msg.Header)
                        match = [];
                    else
                        match = find(strcmpi(name, [msg.Header.Name]));
                    end
                    if isempty(match)
                        error(message('MATLAB:http:NoMatchingField',char(name)));
                    elseif length(match) > 1
                        error(message('MATLAB:http:MoreThanOneField',char(name)));
                    end
                    % Copy name and value properties into existing field.  In the NAME,VALUE usage
                    % of this function, don't just store the whole fields(i) because we don't want
                    % to change its class.
                    if useClasses
                        msg.Header(match) = fields(i);
                    else
                        msg.Header(match).Name = fields(i).Name;
                        msg.Header(match).Value = fields(i).Value;
                    end
                end
                obj(midx) = msg;
            end
            matlab.net.http.internal.nargoutWarning(nargout,mfilename,'changeFields');
        end
        
        function obj = removeFields(obj, varargin)
        % removeFields Remove fields from an HTTP message header
        %   MSG = removeFields(MSG, IDS) returns a copy of the message array MSG with
        %   all header fields matching IDS removed. The IDS can be:
        %     - a character vector, vector of strings, comma-separated list of
        %       strings or character vectors, or cell array of character vectors
        %       naming the fields to be removed.  Names are not case-sensitive.
        %     - a vector of HeaderField or comma-separated list of them, whose names 
        %       are used to determine which fields to remove.  Names are not
        %       case-sensitive and Values of the HeaderFields are ignored.
        %     - a vector of meta.class that are subclasses of HeaderField, or
        %       comma-separated list of them.  For each class, this matches any fields
        %       that are instances of that class (including its subclasses) plus any
        %       fields whose names match the names explicitly supported by the class
        %       or its subclasses.
        %
        %   For example MediaRangeField has two subclasses, AcceptField and
        %   ContentTypeField.  If you specify an ID of
        %   ?matlab.net.http.field.MediaRangeField it will match all fields of
        %   class MediaRangeField, AcceptField and ContentTypeField, plus any fields
        %   with the Name 'Accept' or 'Content-Type' (such as
        %   matlab.net.http.HeaderField or matlab.net.http.field.GenericField).
        %
        % See also HeaderField, addFields, changeFields, getFields
        
            if isempty(varargin)
                return;
            end
            ids = getFieldsVector(varargin);
            if isempty(ids)
                ids = getFieldsVector(varargin,'meta.class');
                if isempty(ids)
                    ids = getNameVector(varargin);
                end
            end
            names = getMatchingNames(ids);
            if isa(ids, 'meta.class')
                classes = ids;
            else
                classes = [];
            end
            for midx = 1 : length(obj)
                header = obj(midx).Header;
                if isempty(header)
                    continue;
                end
                % first remove matching names
                for i = 1 : length(names)
                    header(strcmpi(names(i), [header.Name])) = [];
                end
                % next remove matching classes and their subclasses
                if ~isempty(classes)
                    header(arrayfun(@(h) any(metaclass(h) <= classes), header)) = [];
                end
                obj(midx).Header = header;
            end
            matlab.net.http.internal.nargoutWarning(nargout,mfilename,'removeFields');
        end
        
        function res = char(obj)
        % char Return an HTTP message as a character vector
        %   CHR = char(MSG) converts the message MSG to a character vector.  If MSG is
        %   an array with more than one message, returns a cell array of character
        %   vectors.
        %
        %  For more information, see string.
        %
        % See also string, show
            num = length(obj);
            if num > 1
                res = cell(1,num);
            end
            for i = 1 : num
                field = obj(i);
                sHeader = sprintf('%s\n', char(field.Header));
                if isempty(field.Body) || ...
                        (isempty(field.Body.Data) && isempty(field.Body.Payload))
                    str = sprintf('%s\n%s', char(field.StartLine), sHeader);
                else
                    str = sprintf('%s\n%s%s\n', char(field.StartLine), ...
                                  sHeader, field.Body.char());
                end
                if num > 1
                    res{i} = str;
                else
                    res = str;
                end
            end
        end
        
        function str = string(obj)
        % string Return an HTTP Message as a string
        %   STR = string(MSG) returns the whole message, including Header and Body, as
        %   a string.  If the Body contains binary data (as opposed to character data)
        %   a single line appears indicating the length of the data.
        %
        %   If MSG is an array of messages, returns an array of strings, one per
        %   message.
        %
        %   This method is intended for logging or debugging.
        %
        % See also show, char
            str = string(obj.char());
        end
        
        function str = show(obj, varargin)
        % show Display or return a human-readable version of a message
        %   show(MSG) displays the whole message, including Header and Body, in the
        %   command window.  If MSG is an array with more than one message, displays
        %   all of the messages with dashed lines separating the messages.
        %
        %   show(MSG, MAXLENGTH) displays at most MAXLENGTH characters of the Body.
        %   If the body is longer than this, displays an indication of the total
        %   length of the data in characters and the type of the data.
        %
        %   STR = show(___) returns a string containing the information that would be
        %   displayed.
        %  
        %   If the Body contains binary data that cannot be converted to characters,
        %   show displays or returns a single line for the Body, indicating the
        %   length of the data in bytes.
        %
        %   This method is intended for diagnostics or debugging.
        %
        % See also string, char, Body
            num = length(obj);
            if nargout > 0
                str(num) = string('');
            end
            for i = 1 : length(obj)
                field = obj(i);
                if ~isempty(field.Header)
                    sHeader = sprintf('%s\n', string(field.Header));
                else
                    sHeader = '';
                end
                if i > 1 && nargout == 0
                    fprintf('------------------------------------------\n');
                end
                if isempty(field.Body) || ...
                        (isempty(field.Body.Data) && isempty(field.Body.Payload))
                    if nargout == 0
                        fprintf('%s\n%s', string(field.StartLine), sHeader);
                    else
                        str(i) = sprintf('%s\n%s', string(field.StartLine), sHeader);
                    end
                else
                    if nargout == 0
                        fprintf('%s\n%s\n%s\n', string(field.StartLine), ...
                                  sHeader, field.Body.show(varargin{:}));
                    else
                        str(i) = sprintf('%s\n%s\n%s\n', string(field.StartLine), ...
                                  sHeader, field.Body.show(varargin{:}));
                    end
                end
            end
        end
    end
    
    methods (Access=?matlab.net.http.internal.HTTPConnector, Hidden)
        function obj = setBodyExternal(obj, data)
        % Calls the setBody method from other classes
            obj = setBody(obj, data);
        end
    end
        
    methods (Abstract, Static, Access=protected, Hidden)
        % checkHeader(header) - throw error if the header has any invalid fields
        %   for this message type.  Invoked from set.Header after verifying its type.
        checkHeader(header)
        % checkBody(value) - throw error if the value is not suitable for the body
        %   of this message type.  Invoked from set.Body prior to any verification.
        checkBody(value)
        % getStartLineType - get the specific type of the StartLine for this message.
        %   Returns a string.
        type = getStartLineType()
        % getInvalidFields Check whether the fields are valid for this header
        %   This function is intended to be implemented by subclasses to place
        %   restrictions on fields that are not allowed for the subclass.  It is
        %   invoked by the set method of the Fields property after verifying that the
        %   fields value is a vector of matlab.net.http.HeaderField.  If an invalid
        %   field is found, it returns the invalid field, and the infrastructure will
        %   print the appropriate error message.  If the problem is only with the
        %   field's Name, the subclass should set the Value in the returned field to
        %   [] in order to produce the appropriate message.
        badField = getInvalidFields(fields) 
        % Return true if setting the ContentType header field in this message should
        % also set the ContentType in the Body.  
        tf = shouldSetBodyContentType()
    end
    
    methods (Access=protected, Hidden)
        function res = getSingleField(obj, name)
        % getSingleField returns one header field
        %   FIELD = getSingleField(obj, NAME) returns the HeaderField matching NAME.
        %   Use this method to extract a field that you only expect to appear once in
        %   a message header.  If there is more than one instance of the field, this
        %   errors out.  If the field does not appear in the header, this returns [].
        %    
        %   See also getAllFields
            res = obj.getFields(name);
            if ~isempty(res) && length(res) > 1
                error(message('MATLAB:http:MoreThanOneField', name));
            end
        end
    end       

    methods (Access=private, Sealed)
       function obj = addFieldsPrivate(obj, check, varargin)
        % Add fields to the header, with optional check of validity
        %   obj - a message array
        %   check - if set, any errors thrown by subclass constructors of HeaderField 
        %      will be thrown from this function.  If false, a Generic HeaderField
        %      object will be created if the subclass constructor fails.  
        %   varargin - an optional INDEX plus an array of HeaderField, an array of
        %      structs containing Name/Value fields, or a list of name/value pairs.
            import matlab.net.http.HeaderField;
            if isempty(varargin)
                error(message('MATLAB:minrhs'));
            end
            for midx = 1 : length(obj)
                if isnumeric(varargin{1})
                    where = varargin{1};
                    validateattributes(where, {'numeric'}, {'scalar','integer'}, ...
                        mfilename, 'index');
                    % set where to value in range 1:length(Header)+1
                    if where <= 0
                        % count from end where 0 is end+1
                        where = max(length(obj(midx).Header) + where + 1, 1);
                    else
                        % count from front
                        where = min(length(obj(midx).Header) + 1, where);
                    end
                    varargin(1) = []; % shift varargs left
                else
                    where = length(obj(midx).Header) + 1;
                end
                fields = getFieldsVector(varargin);
                if isempty(fields)
                    if isstruct(varargin{1}) 
                        % if first vararg is a struct, create HeaderField objects from
                        % Name/Value members
                        structs = varargin{1};
                        assert(length(varargin) == 1 && isvector(structs));
                        if check
                            fields = arrayfun(@(s) ...
                                   HeaderField.createHeaderField(s.Name, s.Value), structs, ...
                                   'UniformOutput', false);
                        else
                            fields = arrayfun(@(s) createFieldSafe(s.Name,s.Value), ...
                                                        structs, 'UniformOutput', false);
                        end
                        fields = [fields{:}];
                    else
                        % else, assume varargs is list of name,value pairs
                        npairs = ceil(length(varargin)/2);
                        fields(npairs) = HeaderField();
                        for i = 1 : npairs
                            idx = 2*i-1;
                            name = varargin{idx};
                            if idx == length(varargin)
                                value = [];
                            else
                                value = varargin{idx+1};
                            end 
                            if check
                                fields(i) = HeaderField.createHeaderField(name, value);
                            else
                                fields(i) = createFieldSafe(name, value);
                            end
                        end
                    end
                end
                obj(midx).Header = ...
                    [obj(midx).Header(1:where-1) fields obj(midx).Header(where:end)];
            end
       end
    end

    
    methods (Sealed, Access=protected, Hidden)
        function obj = addFieldsSilent(obj, varargin)
        % addFieldsSilent Add fields without throwing an error
        %   Same as addFields but silently creates a
        %   matlab.net.http.field.GenericField header field if the Value of a field
        %   is inappropriate for its Name.
        %
        %   varargin - an array of matlab.net.http.HeaderField, an array of structs
        %      containing Name/Value fields, or a list of name/value pairs.
        %
        %   See also matlab.net.http.HeaderField, addFields
            obj = obj.addFieldsPrivate(false, varargin{:});
        end
        
        function ct = getBodyContentType(obj)
        % If this message contains a MessageBody, return the MediaType in the
        % Content-Type header field.  If not, return [].  This causes the ContentType
        % of Body to be set to the value of the Content-Type field.
            ct = [];
            if ~isempty(obj.Body)
                ctf = obj.getSingleField('Content-Type');
                if ~isempty(ctf)
                    ct = ctf.convert();
                end
            end
        end
    end
    
    methods (Access={?matlab.net.http.RequestMessage, ...
                     ?matlab.internal.webservices.HTTPConnector, ...
                     ?matlab.net.http.internal.HTTPConnector})
        function obj = addFieldsNoCheck(obj, varargin)
        % addFieldsSilent Add fields to end of header without checking for errors
        %   This function is the same as addFields, except that it does not enforce
        %   any constraints on the names of the fields or their values.  If a
        %   subclass of HeaderField with the specified NAME cannot be constructed due
        %   to an invalid VALUE, it constructs a generic HeaderField object.
        %
        % See also matlab.net.http.Header.addFields, matlab.net.http.HeaderField
            obj = obj.addFieldsSilent(varargin{:});
        end
    end

end

function field = createFieldSafe(name, varargin)
% createFieldSafe  Create a HeaderField of the appropriate subclass from the name and
% value.  If the subclass complains, create one of type matlab.net.http.field.Generic.
    try
        field = matlab.net.http.HeaderField.createHeaderField(name, varargin{:});
    catch
        field = matlab.net.http.field.GenericField(name, varargin{:});
    end
end

function names = getMatchingNames(ids)
% Return vector of names in vector of ids:
%   strings or cell array of strings (names)
%   meta.class (use PackageMonitor.getNamesForClass)
%   HeaderField (use their names)
% Error out if ids is not one of above.
    if ischar(ids) || isstring(ids) || iscell(ids)
        names = matlab.net.internal.getStringVector(ids, mfilename, 'IDS');
    else
        % We want to error out if user specifies HeaderField.empty or a meta.class
        % that doesn't exist (which creates meta.class.empty) with a message that the
        % input was empty, so need to mention 'nonempty' first, before 'vector'.
        validateattributes(ids, {'cell', 'meta.class', 'matlab.net.http.HeaderField', 'string array'}, ...
            {'nonempty','vector'}, mfilename, 'IDS');
        if isa(ids, 'meta.class')
            names = arrayfun(@(c)matlab.net.http.internal.PackageMonitor.getNamesForClass(c), ...
                             ids, 'UniformOutput', false);
            names = [names{:}];
        else
            % input was HeaderField array
            names = [ids.Name];
        end
    end
end

function fields = getFieldsVector(args, type)
% args is a cell array, the varargin from a call to a function.  If it
% contains all HeaderField objects, return them all in a vector.  If a
% mixture, error out.  If no HeaderField objects, return
% matlab.net.http.HeaderField.empty.
%
% if 'type' specified, its the name of a class other than HeaderField, to to
% the above processing.

    if nargin == 1
        type = 'matlab.net.http.HeaderField';
    end
    if any(cellfun(@(a) isa(a, type), args))
        % If any arg is type, try to collapse all args into type vector.
        try
            fields = reshape([args{:}], 1, []);
        catch e
            % didn't work, so error out
            error(message('MATLAB:http:ExpectedAllSameType', type));
        end
    else 
        fields = feval([type '.empty']);
    end
end

function args = getNameVector(args)
% args is the varargin from a call to a function, which must not be empty. If
% first arg is a nonscalar array other than char or cell array, it must be the
% only argument, and we return args{1}, or we error out with "too many input
% arguments".  Otherwise we return args.
    firstArg = args{1};
    if iscell(firstArg) || (~ischar(firstArg) && ~isscalar(firstArg))
        if length(args) > 1
            error(message('MATLAB:maxrhs'));
        end
        args = firstArg;
    end
end