LCOV - code coverage report
Current view: directory - netwerk/protocol/http - nsHttpResponseHead.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 287 245 85.4 %
Date: 2012-06-02 Functions: 22 20 90.9 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* vim:set ts=4 sw=4 sts=4 et cin: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Darin Fisher <darin@netscape.com> (original author)
      25                 :  *   Andreas M. Schneider <clarence@clarence.de>
      26                 :  *   Christian Biesinger <cbiesinger@web.de>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      30                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : #include <stdlib.h>
      43                 : #include "nsHttpResponseHead.h"
      44                 : #include "nsPrintfCString.h"
      45                 : #include "prprf.h"
      46                 : #include "prtime.h"
      47                 : #include "nsCRT.h"
      48                 : 
      49                 : //-----------------------------------------------------------------------------
      50                 : // nsHttpResponseHead <public>
      51                 : //-----------------------------------------------------------------------------
      52                 : 
      53                 : nsresult
      54              28 : nsHttpResponseHead::SetHeader(nsHttpAtom hdr,
      55                 :                               const nsACString &val,
      56                 :                               bool merge)
      57                 : {
      58              28 :     nsresult rv = mHeaders.SetHeader(hdr, val, merge);
      59              28 :     if (NS_FAILED(rv)) return rv;
      60                 : 
      61                 :     // respond to changes in these headers.  we need to reparse the entire
      62                 :     // header since the change may have merged in additional values.
      63              28 :     if (hdr == nsHttp::Cache_Control)
      64               6 :         ParseCacheControl(mHeaders.PeekHeader(hdr));
      65              22 :     else if (hdr == nsHttp::Pragma)
      66               0 :         ParsePragma(mHeaders.PeekHeader(hdr));
      67                 : 
      68              28 :     return NS_OK;
      69                 : }
      70                 : 
      71                 : void
      72               0 : nsHttpResponseHead::SetContentLength(PRInt64 len)
      73                 : {
      74               0 :     mContentLength = len;
      75               0 :     if (!LL_GE_ZERO(len)) // < 0
      76               0 :         mHeaders.ClearHeader(nsHttp::Content_Length);
      77                 :     else
      78               0 :         mHeaders.SetHeader(nsHttp::Content_Length, nsPrintfCString(20, "%lld", len));
      79               0 : }
      80                 : 
      81                 : void
      82            1284 : nsHttpResponseHead::Flatten(nsACString &buf, bool pruneTransients)
      83                 : {
      84            1284 :     if (mVersion == NS_HTTP_VERSION_0_9)
      85               1 :         return;
      86                 : 
      87            1283 :     buf.AppendLiteral("HTTP/");
      88            1283 :     if (mVersion == NS_HTTP_VERSION_1_1)
      89            1252 :         buf.AppendLiteral("1.1 ");
      90                 :     else
      91              31 :         buf.AppendLiteral("1.0 ");
      92                 : 
      93            1283 :     buf.Append(nsPrintfCString("%u", PRUintn(mStatus)) +
      94            2566 :                NS_LITERAL_CSTRING(" ") +
      95            2566 :                mStatusText +
      96            3849 :                NS_LITERAL_CSTRING("\r\n"));
      97                 : 
      98            1283 :     if (!pruneTransients) {
      99               8 :         mHeaders.Flatten(buf, false);
     100               8 :         return;
     101                 :     }
     102                 : 
     103                 :     // otherwise, we need to iterate over the headers and only flatten
     104                 :     // those that are appropriate.
     105            1275 :     PRUint32 i, count = mHeaders.Count();
     106            9230 :     for (i=0; i<count; ++i) {
     107                 :         nsHttpAtom header;
     108            7955 :         const char *value = mHeaders.PeekHeaderAt(i, header);
     109                 : 
     110           61587 :         if (!value || header == nsHttp::Connection
     111            6718 :                    || header == nsHttp::Proxy_Connection
     112            6718 :                    || header == nsHttp::Keep_Alive
     113            6718 :                    || header == nsHttp::WWW_Authenticate
     114            6702 :                    || header == nsHttp::Proxy_Authenticate
     115            6696 :                    || header == nsHttp::Trailer
     116            6696 :                    || header == nsHttp::Transfer_Encoding
     117            6692 :                    || header == nsHttp::Upgrade
     118                 :                    // XXX this will cause problems when we start honoring
     119                 :                    // Cache-Control: no-cache="set-cookie", what to do?
     120            6692 :                    || header == nsHttp::Set_Cookie)
     121            1265 :             continue;
     122                 : 
     123                 :         // otherwise, write out the "header: value\r\n" line
     124            6690 :         buf.Append(nsDependentCString(header.get()) +
     125           13380 :                    NS_LITERAL_CSTRING(": ") +
     126           20070 :                    nsDependentCString(value) +
     127           20070 :                    NS_LITERAL_CSTRING("\r\n"));
     128                 :     }
     129                 : }
     130                 : 
     131                 : nsresult
     132             567 : nsHttpResponseHead::Parse(char *block)
     133                 : {
     134                 : 
     135             567 :     LOG(("nsHttpResponseHead::Parse [this=%x]\n", this));
     136                 : 
     137                 :     // this command works on a buffer as prepared by Flatten, as such it is
     138                 :     // not very forgiving ;-)
     139                 : 
     140             567 :     char *p = PL_strstr(block, "\r\n");
     141             567 :     if (!p)
     142               0 :         return NS_ERROR_UNEXPECTED;
     143                 : 
     144             567 :     *p = 0;
     145             567 :     ParseStatusLine(block);
     146                 : 
     147            2591 :     do {
     148            3158 :         block = p + 2;
     149                 : 
     150            3158 :                 if (*block == 0)
     151                 :                         break;
     152                 : 
     153            2591 :         p = PL_strstr(block, "\r\n");
     154            2591 :         if (!p)
     155               0 :             return NS_ERROR_UNEXPECTED;
     156                 : 
     157            2591 :         *p = 0;
     158            2591 :         ParseHeaderLine(block);
     159                 : 
     160                 :     } while (1);
     161                 : 
     162             567 :     return NS_OK;
     163                 : }
     164                 : 
     165                 : void
     166            3397 : nsHttpResponseHead::ParseStatusLine(const char *line)
     167                 : {
     168                 :     //
     169                 :     // Parse Status-Line:: HTTP-Version SP Status-Code SP Reason-Phrase CRLF
     170                 :     //
     171                 :  
     172                 :     // HTTP-Version
     173            3397 :     ParseVersion(line);
     174                 :     
     175            3397 :     if ((mVersion == NS_HTTP_VERSION_0_9) || !(line = PL_strchr(line, ' '))) {
     176               1 :         mStatus = 200;
     177               1 :         mStatusText.AssignLiteral("OK");
     178                 :     }
     179                 :     else {
     180                 :         // Status-Code
     181            3396 :         mStatus = (PRUint16) atoi(++line);
     182            3396 :         if (mStatus == 0) {
     183               0 :             LOG(("mal-formed response status; assuming status = 200\n"));
     184               0 :             mStatus = 200;
     185                 :         }
     186                 : 
     187                 :         // Reason-Phrase is whatever is remaining of the line
     188            3396 :         if (!(line = PL_strchr(line, ' '))) {
     189               0 :             LOG(("mal-formed response status line; assuming statusText = 'OK'\n"));
     190               0 :             mStatusText.AssignLiteral("OK");
     191                 :         }
     192                 :         else
     193            3396 :             mStatusText = ++line;
     194                 :     }
     195                 : 
     196            3397 :     LOG(("Have status line [version=%u status=%u statusText=%s]\n",
     197                 :         PRUintn(mVersion), PRUintn(mStatus), mStatusText.get()));
     198            3397 : }
     199                 : 
     200                 : nsresult
     201           18781 : nsHttpResponseHead::ParseHeaderLine(const char *line)
     202                 : {
     203           18781 :     nsHttpAtom hdr = {0};
     204                 :     char *val;
     205                 :     nsresult rv;
     206                 :     
     207           18781 :     rv = mHeaders.ParseHeaderLine(line, &hdr, &val);
     208           18781 :     if (NS_FAILED(rv))
     209              11 :         return rv;
     210                 :     
     211                 :     // leading and trailing LWS has been removed from |val|
     212                 : 
     213                 :     // handle some special case headers...
     214           18770 :     if (hdr == nsHttp::Content_Length) {
     215                 :         PRInt64 len;
     216                 :         const char *ignored;
     217                 :         // permit only a single value here.
     218            3388 :         if (nsHttp::ParseInt64(val, &ignored, &len)) {
     219            3382 :             mContentLength = len;
     220                 :         }
     221                 :         else {
     222                 :             // If this is a negative content length then just ignore it 
     223               6 :             LOG(("invalid content-length! %s\n", val));
     224                 :         }
     225                 :     }
     226           15382 :     else if (hdr == nsHttp::Content_Type) {
     227            2251 :         LOG(("ParseContentType [type=%s]\n", val));
     228                 :         bool dummy;
     229            2251 :         net_ParseContentType(nsDependentCString(val),
     230            2251 :                              mContentType, mContentCharset, &dummy);
     231                 :     }
     232           13131 :     else if (hdr == nsHttp::Cache_Control)
     233             146 :         ParseCacheControl(val);
     234           12985 :     else if (hdr == nsHttp::Pragma)
     235               0 :         ParsePragma(val);
     236           18770 :     return NS_OK;
     237                 : }
     238                 : 
     239                 : // From section 13.2.3 of RFC2616, we compute the current age of a cached
     240                 : // response as follows:
     241                 : //
     242                 : //    currentAge = max(max(0, responseTime - dateValue), ageValue)
     243                 : //               + now - requestTime
     244                 : //
     245                 : //    where responseTime == now
     246                 : //
     247                 : // This is typically a very small number.
     248                 : //
     249                 : nsresult
     250             613 : nsHttpResponseHead::ComputeCurrentAge(PRUint32 now,
     251                 :                                       PRUint32 requestTime,
     252                 :                                       PRUint32 *result)
     253                 : {
     254                 :     PRUint32 dateValue;
     255                 :     PRUint32 ageValue;
     256                 : 
     257             613 :     *result = 0;
     258                 : 
     259             613 :     if (NS_FAILED(GetDateValue(&dateValue))) {
     260              22 :         LOG(("nsHttpResponseHead::ComputeCurrentAge [this=%x] "
     261                 :              "Date response header not set!\n", this));
     262                 :         // Assume we have a fast connection and that our clock
     263                 :         // is in sync with the server.
     264              22 :         dateValue = now;
     265                 :     }
     266                 : 
     267                 :     // Compute apparent age
     268             613 :     if (now > dateValue)
     269              79 :         *result = now - dateValue;
     270                 : 
     271                 :     // Compute corrected received age
     272             613 :     if (NS_SUCCEEDED(GetAgeValue(&ageValue)))
     273               0 :         *result = NS_MAX(*result, ageValue);
     274                 : 
     275             613 :     NS_ASSERTION(now >= requestTime, "bogus request time");
     276                 : 
     277                 :     // Compute current age
     278             613 :     *result += (now - requestTime);
     279             613 :     return NS_OK;
     280                 : }
     281                 : 
     282                 : // From section 13.2.4 of RFC2616, we compute the freshness lifetime of a cached
     283                 : // response as follows:
     284                 : //
     285                 : //     freshnessLifetime = max_age_value
     286                 : // <or>
     287                 : //     freshnessLifetime = expires_value - date_value
     288                 : // <or>
     289                 : //     freshnessLifetime = (date_value - last_modified_value) * 0.10
     290                 : // <or>
     291                 : //     freshnessLifetime = 0
     292                 : //
     293                 : nsresult
     294             851 : nsHttpResponseHead::ComputeFreshnessLifetime(PRUint32 *result)
     295                 : {
     296             851 :     *result = 0;
     297                 : 
     298                 :     // Try HTTP/1.1 style max-age directive...
     299             851 :     if (NS_SUCCEEDED(GetMaxAgeValue(result)))
     300              47 :         return NS_OK;
     301                 : 
     302             804 :     *result = 0;
     303                 : 
     304             804 :     PRUint32 date = 0, date2 = 0;
     305             804 :     if (NS_FAILED(GetDateValue(&date)))
     306              29 :         date = NowInSeconds(); // synthesize a date header if none exists
     307                 : 
     308                 :     // Try HTTP/1.0 style expires header...
     309             804 :     if (NS_SUCCEEDED(GetExpiresValue(&date2))) {
     310               5 :         if (date2 > date)
     311               4 :             *result = date2 - date;
     312                 :         // the Expires header can specify a date in the past.
     313               5 :         return NS_OK;
     314                 :     }
     315                 :     
     316                 :     // Fallback on heuristic using last modified header...
     317             799 :     if (NS_SUCCEEDED(GetLastModifiedValue(&date2))) {
     318             490 :         LOG(("using last-modified to determine freshness-lifetime\n"));
     319             490 :         LOG(("last-modified = %u, date = %u\n", date2, date));
     320             490 :         if (date2 <= date) {
     321                 :             // this only makes sense if last-modified is actually in the past
     322             490 :             *result = (date - date2) / 10;
     323             490 :             return NS_OK;
     324                 :         }
     325                 :     }
     326                 : 
     327                 :     // These responses can be cached indefinitely.
     328             309 :     if ((mStatus == 300) || (mStatus == 301)) {
     329              76 :         *result = PRUint32(-1);
     330              76 :         return NS_OK;
     331                 :     }
     332                 : 
     333             233 :     LOG(("nsHttpResponseHead::ComputeFreshnessLifetime [this = %x] "
     334                 :          "Insufficient information to compute a non-zero freshness "
     335                 :          "lifetime!\n", this));
     336                 : 
     337             233 :     return NS_OK;
     338                 : }
     339                 : 
     340                 : bool
     341            1761 : nsHttpResponseHead::MustValidate()
     342                 : {
     343            1761 :     LOG(("nsHttpResponseHead::MustValidate ??\n"));
     344                 : 
     345                 :     // Some response codes are cacheable, but the rest are not.  This switch
     346                 :     // should stay in sync with the list in nsHttpChannel::ProcessResponse
     347            1761 :     switch (mStatus) {
     348                 :         // Success codes
     349                 :     case 200:
     350                 :     case 203:
     351                 :     case 206:
     352                 :         // Cacheable redirects
     353                 :     case 300:
     354                 :     case 301:
     355                 :     case 302:
     356                 :     case 304:
     357                 :     case 307:
     358                 :         break;
     359                 :         // Uncacheable redirects
     360                 :     case 303:
     361                 :     case 305:
     362                 :         // Other known errors
     363                 :     case 401:
     364                 :     case 407:
     365                 :     case 412:
     366                 :     case 416:
     367                 :     default:  // revalidate unknown error pages
     368             630 :         LOG(("Must validate since response is an uncacheable error page\n"));
     369             630 :         return true;
     370                 :     }
     371                 :     
     372                 :     // The no-cache response header indicates that we must validate this
     373                 :     // cached response before reusing.
     374            1131 :     if (NoCache()) {
     375              21 :         LOG(("Must validate since response contains 'no-cache' header\n"));
     376              21 :         return true;
     377                 :     }
     378                 : 
     379                 :     // Likewise, if the response is no-store, then we must validate this
     380                 :     // cached response before reusing.  NOTE: it may seem odd that a no-store
     381                 :     // response may be cached, but indeed all responses are cached in order
     382                 :     // to support File->SaveAs, View->PageSource, and other browser features.
     383            1110 :     if (NoStore()) {
     384               7 :         LOG(("Must validate since response contains 'no-store' header\n"));
     385               7 :         return true;
     386                 :     }
     387                 : 
     388                 :     // Compare the Expires header to the Date header.  If the server sent an
     389                 :     // Expires header with a timestamp in the past, then we must validate this
     390                 :     // cached response before reusing.
     391            1103 :     if (ExpiresInPast()) {
     392               2 :         LOG(("Must validate since Expires < Date\n"));
     393               2 :         return true;
     394                 :     }
     395                 : 
     396            1101 :     LOG(("no mandatory validation requirement\n"));
     397            1101 :     return false;
     398                 : }
     399                 : 
     400                 : bool
     401              50 : nsHttpResponseHead::MustValidateIfExpired()
     402                 : {
     403                 :     // according to RFC2616, section 14.9.4:
     404                 :     //
     405                 :     //  When the must-revalidate directive is present in a response received by a   
     406                 :     //  cache, that cache MUST NOT use the entry after it becomes stale to respond to 
     407                 :     //  a subsequent request without first revalidating it with the origin server.
     408                 :     //
     409              50 :     return HasHeaderValue(nsHttp::Cache_Control, "must-revalidate");
     410                 : }
     411                 : 
     412                 : bool
     413              32 : nsHttpResponseHead::IsResumable()
     414                 : {
     415                 :     // even though some HTTP/1.0 servers may support byte range requests, we're not
     416                 :     // going to bother with them, since those servers wouldn't understand If-Range.
     417                 :     return mVersion >= NS_HTTP_VERSION_1_1 &&
     418              30 :            PeekHeader(nsHttp::Content_Length) && 
     419              54 :           (PeekHeader(nsHttp::ETag) || PeekHeader(nsHttp::Last_Modified)) &&
     420             116 :            HasHeaderValue(nsHttp::Accept_Ranges, "bytes");
     421                 : }
     422                 : 
     423                 : bool
     424            1107 : nsHttpResponseHead::ExpiresInPast()
     425                 : {
     426                 :     PRUint32 maxAgeVal, expiresVal, dateVal;
     427                 :     
     428                 :     // Bug #203271. Ensure max-age directive takes precedence over Expires
     429            1107 :     if (NS_SUCCEEDED(GetMaxAgeValue(&maxAgeVal))) {
     430              77 :         return false;
     431                 :     }
     432                 :     
     433            1030 :     return NS_SUCCEEDED(GetExpiresValue(&expiresVal)) &&
     434              12 :            NS_SUCCEEDED(GetDateValue(&dateVal)) &&
     435            1042 :            expiresVal < dateVal;
     436                 : }
     437                 : 
     438                 : nsresult
     439               8 : nsHttpResponseHead::UpdateHeaders(nsHttpHeaderArray &headers)
     440                 : {
     441               8 :     LOG(("nsHttpResponseHead::UpdateHeaders [this=%x]\n", this));
     442                 : 
     443               8 :     PRUint32 i, count = headers.Count();
     444              58 :     for (i=0; i<count; ++i) {
     445                 :         nsHttpAtom header;
     446              50 :         const char *val = headers.PeekHeaderAt(i, header);
     447                 : 
     448              50 :         if (!val) {
     449               0 :             continue;
     450                 :         }
     451                 : 
     452                 :         // Ignore any hop-by-hop headers...
     453             662 :         if (header == nsHttp::Connection          ||
     454              42 :             header == nsHttp::Proxy_Connection    ||
     455              42 :             header == nsHttp::Keep_Alive          ||
     456              42 :             header == nsHttp::Proxy_Authenticate  ||
     457              42 :             header == nsHttp::Proxy_Authorization || // not a response header!
     458              42 :             header == nsHttp::TE                  ||
     459              42 :             header == nsHttp::Trailer             ||
     460              42 :             header == nsHttp::Transfer_Encoding   ||
     461              42 :             header == nsHttp::Upgrade             ||
     462                 :         // Ignore any non-modifiable headers...
     463              42 :             header == nsHttp::Content_Location    ||
     464              42 :             header == nsHttp::Content_MD5         ||
     465              42 :             header == nsHttp::ETag                ||
     466                 :         // Assume Cache-Control: "no-transform"
     467              39 :             header == nsHttp::Content_Encoding    ||
     468              39 :             header == nsHttp::Content_Range       ||
     469              37 :             header == nsHttp::Content_Type        ||
     470                 :         // Ignore wacky headers too...
     471                 :             // this one is for MS servers that send "Content-Length: 0"
     472                 :             // on 304 responses
     473              35 :             header == nsHttp::Content_Length) {
     474              23 :             LOG(("ignoring response header [%s: %s]\n", header.get(), val));
     475                 :         }
     476                 :         else {
     477              27 :             LOG(("new response header [%s: %s]\n", header.get(), val));
     478                 : 
     479                 :             // overwrite the current header value with the new value...
     480              27 :             SetHeader(header, nsDependentCString(val));
     481                 :         }
     482                 :     }
     483                 : 
     484               8 :     return NS_OK;
     485                 : }
     486                 : 
     487                 : void
     488            3397 : nsHttpResponseHead::Reset()
     489                 : {
     490            3397 :     LOG(("nsHttpResponseHead::Reset\n"));
     491                 : 
     492            3397 :     ClearHeaders();
     493                 : 
     494            3397 :     mVersion = NS_HTTP_VERSION_1_1;
     495            3397 :     mStatus = 200;
     496            3397 :     mContentLength = LL_MAXUINT;
     497            3397 :     mCacheControlNoStore = false;
     498            3397 :     mCacheControlNoCache = false;
     499            3397 :     mPragmaNoCache = false;
     500            3397 :     mStatusText.Truncate();
     501            3397 :     mContentType.Truncate();
     502            3397 :     mContentCharset.Truncate();
     503            3397 : }
     504                 : 
     505                 : nsresult
     506            2228 : nsHttpResponseHead::ParseDateHeader(nsHttpAtom header, PRUint32 *result)
     507                 : {
     508            2228 :     const char *val = PeekHeader(header);
     509            2228 :     if (!val)
     510             360 :         return NS_ERROR_NOT_AVAILABLE;
     511                 : 
     512                 :     PRTime time;
     513            1868 :     PRStatus st = PR_ParseTimeString(val, true, &time);
     514            1868 :     if (st != PR_SUCCESS)
     515               0 :         return NS_ERROR_NOT_AVAILABLE;
     516                 : 
     517            1868 :     *result = PRTimeToSeconds(time); 
     518            1868 :     return NS_OK;
     519                 : }
     520                 : 
     521                 : nsresult
     522             613 : nsHttpResponseHead::GetAgeValue(PRUint32 *result)
     523                 : {
     524             613 :     const char *val = PeekHeader(nsHttp::Age);
     525             613 :     if (!val)
     526             613 :         return NS_ERROR_NOT_AVAILABLE;
     527                 : 
     528               0 :     *result = (PRUint32) atoi(val);
     529               0 :     return NS_OK;
     530                 : }
     531                 : 
     532                 : // Return the value of the (HTTP 1.1) max-age directive, which itself is a
     533                 : // component of the Cache-Control response header
     534                 : nsresult
     535            1969 : nsHttpResponseHead::GetMaxAgeValue(PRUint32 *result)
     536                 : {
     537            1969 :     const char *val = PeekHeader(nsHttp::Cache_Control);
     538            1969 :     if (!val)
     539            1815 :         return NS_ERROR_NOT_AVAILABLE;
     540                 : 
     541             154 :     const char *p = PL_strcasestr(val, "max-age=");
     542             154 :     if (!p)
     543              25 :         return NS_ERROR_NOT_AVAILABLE;
     544                 : 
     545             129 :     int maxAgeValue = atoi(p + 8);
     546             129 :     if (maxAgeValue < 0)
     547               0 :         maxAgeValue = 0;
     548             129 :     *result = PRUint32(maxAgeValue);
     549             129 :     return NS_OK;
     550                 : }
     551                 : 
     552                 : nsresult
     553            1850 : nsHttpResponseHead::GetExpiresValue(PRUint32 *result)
     554                 : {
     555            1850 :     const char *val = PeekHeader(nsHttp::Expires);
     556            1850 :     if (!val)
     557            1828 :         return NS_ERROR_NOT_AVAILABLE;
     558                 : 
     559                 :     PRTime time;
     560              22 :     PRStatus st = PR_ParseTimeString(val, true, &time);
     561              22 :     if (st != PR_SUCCESS) {
     562                 :         // parsing failed... RFC 2616 section 14.21 says we should treat this
     563                 :         // as an expiration time in the past.
     564               0 :         *result = 0;
     565               0 :         return NS_OK;
     566                 :     }
     567                 : 
     568              22 :     if (LL_CMP(time, <, LL_Zero()))
     569               0 :         *result = 0;
     570                 :     else
     571              22 :         *result = PRTimeToSeconds(time); 
     572              22 :     return NS_OK;
     573                 : }
     574                 : 
     575                 : PRInt64
     576              33 : nsHttpResponseHead::TotalEntitySize()
     577                 : {
     578              33 :     const char* contentRange = PeekHeader(nsHttp::Content_Range);
     579              33 :     if (!contentRange)
     580              23 :         return ContentLength();
     581                 : 
     582                 :     // Total length is after a slash
     583              10 :     const char* slash = strrchr(contentRange, '/');
     584              10 :     if (!slash)
     585               0 :         return -1; // No idea what the length is
     586                 : 
     587              10 :     slash++;
     588              10 :     if (*slash == '*') // Server doesn't know the length
     589               0 :         return -1;
     590                 : 
     591                 :     PRInt64 size;
     592              10 :     if (!nsHttp::ParseInt64(slash, &size))
     593               0 :         size = LL_MAXUINT;
     594              10 :     return size;
     595                 : }
     596                 : 
     597                 : //-----------------------------------------------------------------------------
     598                 : // nsHttpResponseHead <private>
     599                 : //-----------------------------------------------------------------------------
     600                 : 
     601                 : void
     602            3397 : nsHttpResponseHead::ParseVersion(const char *str)
     603                 : {
     604                 :     // Parse HTTP-Version:: "HTTP" "/" 1*DIGIT "." 1*DIGIT
     605                 : 
     606            3397 :     LOG(("nsHttpResponseHead::ParseVersion [version=%s]\n", str));
     607                 : 
     608                 :     // make sure we have HTTP at the beginning
     609            3397 :     if (PL_strncasecmp(str, "HTTP", 4) != 0) {
     610               1 :         LOG(("looks like a HTTP/0.9 response\n"));
     611               1 :         mVersion = NS_HTTP_VERSION_0_9;
     612               1 :         return;
     613                 :     }
     614            3396 :     str += 4;
     615                 : 
     616            3396 :     if (*str != '/') {
     617               0 :         LOG(("server did not send a version number; assuming HTTP/1.0\n"));
     618                 :         // NCSA/1.5.2 has a bug in which it fails to send a version number
     619                 :         // if the request version is HTTP/1.1, so we fall back on HTTP/1.0
     620               0 :         mVersion = NS_HTTP_VERSION_1_0;
     621               0 :         return;
     622                 :     }
     623                 : 
     624            3396 :     char *p = PL_strchr(str, '.');
     625            3396 :     if (p == nsnull) {
     626               0 :         LOG(("mal-formed server version; assuming HTTP/1.0\n"));
     627               0 :         mVersion = NS_HTTP_VERSION_1_0;
     628               0 :         return;
     629                 :     }
     630                 : 
     631            3396 :     ++p; // let b point to the minor version
     632                 : 
     633            3396 :     int major = atoi(str + 1);
     634            3396 :     int minor = atoi(p);
     635                 : 
     636            3396 :     if ((major > 1) || ((major == 1) && (minor >= 1)))
     637                 :         // at least HTTP/1.1
     638            3353 :         mVersion = NS_HTTP_VERSION_1_1;
     639                 :     else
     640                 :         // treat anything else as version 1.0
     641              43 :         mVersion = NS_HTTP_VERSION_1_0;
     642                 : }
     643                 : 
     644                 : void
     645             152 : nsHttpResponseHead::ParseCacheControl(const char *val)
     646                 : {
     647             152 :     if (!(val && *val)) {
     648                 :         // clear flags
     649               0 :         mCacheControlNoCache = false;
     650               0 :         mCacheControlNoStore = false;
     651               0 :         return;
     652                 :     }
     653                 : 
     654                 :     // search header value for occurrence(s) of "no-cache" but ignore
     655                 :     // occurrence(s) of "no-cache=blah"
     656             152 :     if (nsHttp::FindToken(val, "no-cache", HTTP_HEADER_VALUE_SEPS))
     657              25 :         mCacheControlNoCache = true;
     658                 : 
     659                 :     // search header value for occurrence of "no-store" 
     660             152 :     if (nsHttp::FindToken(val, "no-store", HTTP_HEADER_VALUE_SEPS))
     661              11 :         mCacheControlNoStore = true;
     662                 : }
     663                 : 
     664                 : void
     665               0 : nsHttpResponseHead::ParsePragma(const char *val)
     666                 : {
     667               0 :     LOG(("nsHttpResponseHead::ParsePragma [val=%s]\n", val));
     668                 : 
     669               0 :     if (!(val && *val)) {
     670                 :         // clear no-cache flag
     671               0 :         mPragmaNoCache = false;
     672               0 :         return;
     673                 :     }
     674                 : 
     675                 :     // Although 'Pragma: no-cache' is not a standard HTTP response header (it's
     676                 :     // a request header), caching is inhibited when this header is present so
     677                 :     // as to match existing Navigator behavior.
     678               0 :     if (nsHttp::FindToken(val, "no-cache", HTTP_HEADER_VALUE_SEPS))
     679               0 :         mPragmaNoCache = true;
     680                 : }

Generated by: LCOV version 1.7