Example #1
0
/*----------------------------------------------------------------------
|   PLT_HttpServer::ServeFile
+---------------------------------------------------------------------*/
NPT_Result 
PLT_HttpServer::ServeFile(const NPT_HttpRequest&        request, 
                          const NPT_HttpRequestContext& context,
                          NPT_HttpResponse&             response,
                          NPT_String                    file_path) 
{
    NPT_InputStreamReference stream;
    NPT_File                 file(file_path);
    NPT_FileInfo             file_info;
    
    // prevent hackers from accessing files outside of our root
    if ((file_path.Find("/..") >= 0) || (file_path.Find("\\..") >= 0) ||
        NPT_FAILED(NPT_File::GetInfo(file_path, &file_info))) {
        return NPT_ERROR_NO_SUCH_ITEM;
    }
    
    // check for range requests
    const NPT_String* range_spec = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_RANGE);
    
    // handle potential 304 only if range header not set
    NPT_DateTime  date;
    NPT_TimeStamp timestamp;
    if (NPT_SUCCEEDED(PLT_UPnPMessageHelper::GetIfModifiedSince((NPT_HttpMessage&)request, date)) &&
        !range_spec) {
        date.ToTimeStamp(timestamp);
        
        NPT_LOG_INFO_5("File %s timestamps: request=%d (%s) vs file=%d (%s)", 
                       (const char*)request.GetUrl().GetPath(),
                       (NPT_UInt32)timestamp.ToSeconds(),
                       (const char*)date.ToString(),
                       (NPT_UInt32)file_info.m_ModificationTime,
                       (const char*)NPT_DateTime(file_info.m_ModificationTime).ToString());
        
        if (timestamp >= file_info.m_ModificationTime) {
            // it's a match
            NPT_LOG_FINE_1("Returning 304 for %s", request.GetUrl().GetPath().GetChars());
            response.SetStatus(304, "Not Modified", NPT_HTTP_PROTOCOL_1_1);
            return NPT_SUCCESS;
        }
    }
    
    // open file
    if (NPT_FAILED(file.Open(NPT_FILE_OPEN_MODE_READ)) || 
        NPT_FAILED(file.GetInputStream(stream))        ||
        stream.IsNull()) {
        return NPT_ERROR_NO_SUCH_ITEM;
    }
    
    // set Last-Modified and Cache-Control headers
    if (file_info.m_ModificationTime) {
        NPT_DateTime last_modified = NPT_DateTime(file_info.m_ModificationTime);
        response.GetHeaders().SetHeader("Last-Modified", last_modified.ToString(NPT_DateTime::FORMAT_RFC_1123), true);
        response.GetHeaders().SetHeader("Cache-Control", "max-age=0,must-revalidate", true);
        //response.GetHeaders().SetHeader("Cache-Control", "max-age=1800", true);
    }
    
    PLT_HttpRequestContext tmp_context(request, context);
    return ServeStream(request, context, response, stream, PLT_MimeType::GetMimeType(file_path, &tmp_context));
}
/*----------------------------------------------------------------------
|   TestRandom
+---------------------------------------------------------------------*/
static void
TestRandom()
{
    for (unsigned int i=0; i<10000; i++) {
        NPT_TimeStamp ts((double)NPT_System::GetRandomInteger());
        NPT_TimeStamp ts2;
        NPT_DateTime date;
        SHOULD_SUCCEED(date.FromTimeStamp(ts, false));
        SHOULD_SUCCEED(date.ToTimeStamp(ts2));
        NPT_String ds;
        NPT_DateTime ndate;
        ds = date.ToString(NPT_DateTime::FORMAT_ANSI);
        ndate.FromString(ds);
        //SHOULD_EQUAL(date, ndate);
        SHOULD_SUCCEED(ndate.ToTimeStamp(ts2));
        SHOULD_EQUAL_F((double)ts2.ToSeconds(), (double)ts.ToSeconds());
        
        ds = date.ToString(NPT_DateTime::FORMAT_W3C);
        ndate.FromString(ds);
        //SHOULD_EQUAL(date, ndate);
        SHOULD_SUCCEED(ndate.ToTimeStamp(ts2));
        SHOULD_EQUAL_F((double)ts2.ToSeconds(), (double)ts.ToSeconds());

        ds = date.ToString(NPT_DateTime::FORMAT_RFC_1123);
        ndate.FromString(ds);
        //SHOULD_EQUAL(date, ndate);
        SHOULD_SUCCEED(ndate.ToTimeStamp(ts2));
        SHOULD_EQUAL_F((double)ts2.ToSeconds(), (double)ts.ToSeconds());

        ds = date.ToString(NPT_DateTime::FORMAT_RFC_1036);
        ndate.FromString(ds);
        //SHOULD_EQUAL(date, ndate);
        SHOULD_SUCCEED(ndate.ToTimeStamp(ts2));
        SHOULD_EQUAL_F((double)ts2.ToSeconds(), (double)ts.ToSeconds());
    }
}