PassRefPtr<Blob> Blob::slice(long long start, long long length) const
{
    // When we slice a file for the first time, we obtain a snapshot of the file by capturing its current size and modification time.
    // The modification time will be used to verify if the file has been changed or not, when the underlying data are accessed.
    long long snapshotSize;
    double snapshotModificationTime;
    if (m_snapshotCaptured) {
        snapshotSize = m_snapshotSize;
        snapshotModificationTime = m_snapshotModificationTime;
    } else {
        // If we fail to retrieve the size or modification time, probably due to that the file has been deleted, an empty blob will be returned.
        time_t modificationTime;
        if (!getFileSize(m_path, snapshotSize) || !getFileModificationTime(m_path, modificationTime)) {
            snapshotSize = 0;
            snapshotModificationTime = 0;
        } else
            snapshotModificationTime = modificationTime;
    }

    // Clamp the range if it exceeds the size limit.
    if (start < 0)
        start = 0;
    if (length < 0)
        length = 0;

    if (start > snapshotSize) {
        start = 0;
        length = 0;
    } else if (start + length > snapshotSize)
        length = snapshotSize - start;

    return adoptRef(new Blob(m_path, m_start + start, length, snapshotSize, snapshotModificationTime));
}
Ejemplo n.º 2
0
static void removeAllDatabasesForOriginPath(const String& originPath, std::chrono::system_clock::time_point modifiedSince)
{
    Vector<String> databasePaths = listDirectory(originPath, "*");

    for (auto& databasePath : databasePaths) {
        String databaseFile = pathByAppendingComponent(databasePath, "IndexedDB.sqlite3");

        if (!fileExists(databaseFile))
            continue;

        if (modifiedSince > std::chrono::system_clock::time_point::min()) {
            time_t modificationTime;
            if (!getFileModificationTime(databaseFile, modificationTime))
                continue;

            if (std::chrono::system_clock::from_time_t(modificationTime) < modifiedSince)
                continue;
        }

        SQLiteFileSystem::deleteDatabaseFile(databaseFile);
        deleteEmptyDirectory(databasePath);
    }

    deleteEmptyDirectory(originPath);
}
Ejemplo n.º 3
0
static void removeAllDatabasesForOriginPath(const String& originPath, double startDate, double endDate)
{
    // FIXME: We should also close/invalidate any live handles to the database files we are about to delete.
    // Right now:
    //     - For read-only operations, they will continue functioning as normal on the unlinked file.
    //     - For write operations, they will start producing errors as SQLite notices the missing backing store.
    // This is tracked by https://bugs.webkit.org/show_bug.cgi?id=135347

    Vector<String> databasePaths = listDirectory(originPath, "*");

    for (auto& databasePath : databasePaths) {
        String databaseFile = pathByAppendingComponent(databasePath, "IndexedDB.sqlite3");

        if (!fileExists(databaseFile))
            continue;

        time_t modTime;
        getFileModificationTime(databaseFile, modTime);

        if (modTime < startDate || modTime > endDate)
            continue;

        deleteFile(databaseFile);
        deleteEmptyDirectory(databasePath);
    }

    deleteEmptyDirectory(originPath);
}
Ejemplo n.º 4
0
void DatabaseTracker::deleteDatabasesModifiedSince(std::chrono::system_clock::time_point time)
{
    Vector<RefPtr<SecurityOrigin>> originsCopy;
    origins(originsCopy);

    for (auto& origin : originsCopy) {
        Vector<String> databaseNames;
        if (!databaseNamesForOrigin(origin.get(), databaseNames))
            continue;

        size_t deletedDatabases = 0;

        for (auto& databaseName : databaseNames) {
            auto fullPath = fullPathForDatabase(origin.get(), databaseName, false);

            time_t modificationTime;
            if (!getFileModificationTime(fullPath, modificationTime))
                continue;

            if (modificationTime < std::chrono::system_clock::to_time_t(time))
                continue;

            deleteDatabase(origin.get(), databaseName);
            ++deletedDatabases;
        }

        if (deletedDatabases == databaseNames.size())
            deleteOrigin(origin.get());
    }
}
Ejemplo n.º 5
0
void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const
{
    unsigned long flashPlayerPluginPathUTF8ByteLen = 0;
    unsigned char* const flashPlayerPluginPathUTF8Bytes = WebKitApollo::g_HostFunctions->getFlashPlayerPluginPathUTF8Bytes(&flashPlayerPluginPathUTF8ByteLen);
    ASSERT(flashPlayerPluginPathUTF8Bytes);
    ASSERT(flashPlayerPluginPathUTF8ByteLen > 0);

    String flashPlayerPluginPath(UTF8Encoding().decode(reinterpret_cast<const char*>(flashPlayerPluginPathUTF8Bytes), flashPlayerPluginPathUTF8ByteLen));
    WebKitApollo::g_HostFunctions->freeBytes(flashPlayerPluginPathUTF8Bytes);

    time_t lastModified;
    if (getFileModificationTime(flashPlayerPluginPath, lastModified))
    {
        paths.add(flashPlayerPluginPath);
    }

    // Adobe Reader
    
    WebString* pdfPluginPath = WebKitApollo::g_HostFunctions->getPDFPluginPathWebString();
    if(pdfPluginPath)
    {
        paths.add(adoptWebString(pdfPluginPath));
    }
    
}
static Optional<time_t> fileModificationTime(const String& filePath)
{
    time_t time;
    if (!getFileModificationTime(filePath, time))
        return Nullopt;

    return time;
}
Ejemplo n.º 7
0
double File::lastModifiedDate() const
{
    time_t modificationTime;
    if (getFileModificationTime(m_path, modificationTime) && isValidFileTime(modificationTime))
        return modificationTime * msPerSecond;

    return currentTime() * msPerSecond;
}
double File::lastModifiedDate() const
{
    time_t modificationTime;
    if (!getFileModificationTime(m_path, modificationTime))
        return 0;

    // Needs to return epoch time in milliseconds for Date.
    return modificationTime * 1000.0;
}
Ejemplo n.º 9
0
void FileStream::openForRead(Blob* blob)
{
    ASSERT(!isMainThread());

    if (isHandleValid(m_handle))
        return;

    // FIXME: Need to handle multiple items that may include non-file ones when BlobBuilder is introduced.
    ASSERT(blob->items().size() >= 1);
    const FileBlobItem* fileItem = blob->items().at(0)->toFileBlobItem();
    if (!fileItem) {
        ASSERT(false);
        m_client->didFail(NOT_READABLE_ERR);
        return;
    }

    // Check if the file exists by querying its modification time. We choose not to call fileExists() in order to save an
    // extra file system call when the modification time is needed to check the validity of the sliced file blob.
    // Per the spec, we need to return different error codes to differentiate between non-existent file and permission error.
    // openFile() could not tell use the failure reason.
    time_t currentModificationTime;
    if (!getFileModificationTime(fileItem->path(), currentModificationTime)) {
        m_client->didFail(NOT_FOUND_ERR);
        return;
    }

    // Open the file blob.
    m_handle = openFile(fileItem->path(), OpenForRead);
    if (!isHandleValid(m_handle)) {
        m_client->didFail(NOT_READABLE_ERR);
        return;
    }

#if ENABLE(BLOB_SLICE)
    const FileRangeBlobItem* fileRangeItem = fileItem->toFileRangeBlobItem();
    if (fileRangeItem) {
        // Check the modificationt time for the possible file change.
        if (static_cast<time_t>(fileRangeItem->snapshotModificationTime()) != currentModificationTime) {
            m_client->didFail(NOT_READABLE_ERR);
            return;
        }

        // Jump to the beginning position if the file has been sliced.
        if (fileRangeItem->start() > 0) {
            if (seekFile(m_handle, fileRangeItem->start(), SeekFromBeginning) < 0) {
                m_client->didFail(NOT_READABLE_ERR);
                return;
            }
        }
    }
#endif

    // Get the size.
    m_totalBytesToRead = blob->size();
    m_client->didGetSize(m_totalBytesToRead);
}
Ejemplo n.º 10
0
double File::lastModifiedMS() const {
  if (hasValidSnapshotMetadata() &&
      isValidFileTime(m_snapshotModificationTimeMS))
    return m_snapshotModificationTimeMS;

  double modificationTimeMS;
  if (hasBackingFile() && getFileModificationTime(m_path, modificationTimeMS) &&
      isValidFileTime(modificationTimeMS))
    return modificationTimeMS;

  return currentTimeMS();
}
void File::captureSnapshot(long long& snapshotSize, double& snapshotModificationTime) const
{
    // Obtains a snapshot of the file by capturing its current size and modification time. This is used when we slice a file for the first time.
    // If we fail to retrieve the size or modification time, probably due to that the file has been deleted, 0 size is returned.
    // FIXME: Combine getFileSize and getFileModificationTime into one file system call.
    time_t modificationTime;
    if (!getFileSize(m_path, snapshotSize) || !getFileModificationTime(m_path, modificationTime)) {
        snapshotSize = 0;
        snapshotModificationTime = 0;
    } else
        snapshotModificationTime = modificationTime;
}
Ejemplo n.º 12
0
// Return false if we cannot advance the stream. Currently the only possible failure is that the underlying file has been removed or changed since File.slice.
static bool advanceCurrentStream(FormStreamFields* form)
{
    closeCurrentStream(form);

    if (form->remainingElements.isEmpty())
        return true;

    // Create the new stream.
    FormDataElement& nextInput = form->remainingElements.last();

    if (nextInput.m_type == FormDataElement::data) {
        size_t size = nextInput.m_data.size();
        MallocPtr<char> data = nextInput.m_data.releaseBuffer();
        form->currentStream = CFReadStreamCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data.get()), size, kCFAllocatorNull);
        form->currentData = std::move(data);
    } else {
#if ENABLE(BLOB)
        // Check if the file has been changed or not if required.
        if (isValidFileTime(nextInput.m_expectedFileModificationTime)) {
            time_t fileModificationTime;
            if (!getFileModificationTime(nextInput.m_filename, fileModificationTime) || fileModificationTime != static_cast<time_t>(nextInput.m_expectedFileModificationTime))
                return false;
        }
#endif
        const String& path = nextInput.m_shouldGenerateFile ? nextInput.m_generatedFilename : nextInput.m_filename;
        form->currentStream = CFReadStreamCreateWithFile(0, pathAsURL(path).get());
        if (!form->currentStream) {
            // The file must have been removed or become unreadable.
            return false;
        }
#if ENABLE(BLOB)
        if (nextInput.m_fileStart > 0) {
            RetainPtr<CFNumberRef> position = adoptCF(CFNumberCreate(0, kCFNumberLongLongType, &nextInput.m_fileStart));
            CFReadStreamSetProperty(form->currentStream, kCFStreamPropertyFileCurrentOffset, position.get());
        }
        form->currentStreamRangeLength = nextInput.m_fileLength;
#endif
    }
    form->remainingElements.removeLast();

    // Set up the callback.
    CFStreamClientContext context = { 0, form, 0, 0, 0 };
    CFReadStreamSetClient(form->currentStream, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
        formEventCallback, &context);

    // Schedule with the current set of run loops.
    SchedulePairHashSet::iterator end = form->scheduledRunLoopPairs.end();
    for (SchedulePairHashSet::iterator it = form->scheduledRunLoopPairs.begin(); it != end; ++it)
        CFReadStreamScheduleWithRunLoop(form->currentStream, (*it)->runLoop(), (*it)->mode());

    return true;
}
double File::lastModifiedDate() const
{
#if ENABLE(FILE_SYSTEM)
    if (hasValidSnapshotMetadata() && isValidFileTime(m_snapshotModificationTime))
        return m_snapshotModificationTime * msPerSecond;
#endif

    time_t modificationTime;
    if (getFileModificationTime(m_path, modificationTime) && isValidFileTime(modificationTime))
        return modificationTime * msPerSecond;

    return currentTime() * msPerSecond;
}
Ejemplo n.º 14
0
double File::lastModifiedDate() const
{
#if ENABLE(FILE_SYSTEM)
    if (m_snapshotSize >= 0 && m_snapshotModificationTime)
        return m_snapshotModificationTime * 1000.0;
#endif

    time_t modificationTime;
    if (!getFileModificationTime(m_path, modificationTime))
        return 0;

    // Needs to return epoch time in milliseconds for Date.
    return modificationTime * 1000.0;
}
Ejemplo n.º 15
0
double File::lastModifiedDate() const
{
#if ENABLE(FILE_SYSTEM)
    if (hasValidSnapshotMetadata())
        return m_snapshotModificationTime * 1000.0;
#endif

    time_t modificationTime;
    if (!getFileModificationTime(m_path, modificationTime))
        return invalidFileTime();

    // Needs to return epoch time in milliseconds for Date.
    return modificationTime * 1000.0;
}
Ejemplo n.º 16
0
long long FileStream::getSize(const String& path, double expectedModificationTime)
{
    // Check the modification time for the possible file change.
    time_t modificationTime;
    if (!getFileModificationTime(path, modificationTime))
        return -1;
    if (expectedModificationTime) {
        if (static_cast<time_t>(expectedModificationTime) != modificationTime)
            return -1;
    }

    // Now get the file size.
    long long length;
    if (!getFileSize(path, length))
        return -1;

    return length;
}
Ejemplo n.º 17
0
const String& Page::userStyleSheet() const
{
    if (m_userStyleSheetPath.isEmpty()) {
        ASSERT(m_userStyleSheet.isEmpty());
        return m_userStyleSheet;
    }

    time_t modTime;
    if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
        // The stylesheet either doesn't exist, was just deleted, or is
        // otherwise unreadable. If we've read the stylesheet before, we should
        // throw away that data now as it no longer represents what's on disk.
        m_userStyleSheet = String();
        return m_userStyleSheet;
    }

    // If the stylesheet hasn't changed since the last time we read it, we can
    // just return the old data.
    if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
        return m_userStyleSheet;

    m_didLoadUserStyleSheet = true;
    m_userStyleSheet = String();
    m_userStyleSheetModificationTime = modTime;

    // FIXME: It would be better to load this asynchronously to avoid blocking
    // the process, but we will first need to create an asynchronous loading
    // mechanism that is not tied to a particular Frame. We will also have to
    // determine what our behavior should be before the stylesheet is loaded
    // and what should happen when it finishes loading, especially with respect
    // to when the load event fires, when Document::close is called, and when
    // layout/paint are allowed to happen.
    RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
    if (!data)
        return m_userStyleSheet;

    m_userStyleSheet = TextResourceDecoder::create("text/css")->decode(data->data(), data->size());

    return m_userStyleSheet;
}
Ejemplo n.º 18
0
void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const
{
    unsigned long flashPlayerPluginPathUTF8ByteLen = 0;
    unsigned char* const flashPlayerPluginPathUTF8Bytes = WebKitApollo::g_HostFunctions->getFlashPlayerPluginPathUTF8Bytes(&flashPlayerPluginPathUTF8ByteLen);
    ASSERT(flashPlayerPluginPathUTF8Bytes);
    ASSERT(flashPlayerPluginPathUTF8ByteLen > 0);

    String flashPlayerPluginPath(UTF8Encoding().decode(reinterpret_cast<const char*>(flashPlayerPluginPathUTF8Bytes), flashPlayerPluginPathUTF8ByteLen));
    WebKitApollo::g_HostFunctions->freeBytes(flashPlayerPluginPathUTF8Bytes);

    time_t lastModified;
    if (getFileModificationTime(flashPlayerPluginPath, lastModified))
    {
#if PLATFORM(APOLLO) && !CPU(X86_64)  // loading the flashplayer plugin is not supported yet on Win64
		paths.add(flashPlayerPluginPath);
#endif
    }

    WebString* pdfPluginPath = WebKitApollo::g_HostFunctions->getPDFPluginPathWebString();
    if(pdfPluginPath)
    {
        paths.add(adoptWebString(pdfPluginPath));
    }
}
Ejemplo n.º 19
0
bool PluginDatabase::refresh()
{
#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
    if (!m_persistentMetadataCacheIsLoaded)
        loadPersistentMetadataCache();
#endif
    bool pluginSetChanged = false;

    if (!m_plugins.isEmpty()) {
        PluginSet pluginsToUnload;
        getDeletedPlugins(pluginsToUnload);

        // Unload plugins
        PluginSet::const_iterator end = pluginsToUnload.end();
        for (PluginSet::const_iterator it = pluginsToUnload.begin(); it != end; ++it)
            remove(it->get());

        pluginSetChanged = !pluginsToUnload.isEmpty();
    }

    HashSet<String> paths;
    getPluginPathsInDirectories(paths);

    HashMap<String, time_t> pathsWithTimes;

    // We should only skip unchanged files if we didn't remove any plugins above. If we did remove
    // any plugins, we need to look at every plugin file so that, e.g., if the user has two versions
    // of RealPlayer installed and just removed the newer one, we'll pick up the older one.
    bool shouldSkipUnchangedFiles = !pluginSetChanged;

    HashSet<String>::const_iterator pathsEnd = paths.end();
    for (HashSet<String>::const_iterator it = paths.begin(); it != pathsEnd; ++it) {
        time_t lastModified;
        if (!getFileModificationTime(*it, lastModified))
            continue;

        pathsWithTimes.add(*it, lastModified);

        // If the path's timestamp hasn't changed since the last time we ran refresh(), we don't have to do anything.
        if (shouldSkipUnchangedFiles && m_pluginPathsWithTimes.get(*it) == lastModified)
            continue;

        if (RefPtr<PluginPackage> oldPackage = m_pluginsByPath.get(*it)) {
            ASSERT(!shouldSkipUnchangedFiles || oldPackage->lastModified() != lastModified);
            remove(oldPackage.get());
        }

        RefPtr<PluginPackage> package = PluginPackage::createPackage(*it, lastModified);
        if (package && add(package.release()))
            pluginSetChanged = true;
    }

    // Cache all the paths we found with their timestamps for next time.
    pathsWithTimes.swap(m_pluginPathsWithTimes);

    if (!pluginSetChanged)
        return false;

#if ENABLE(NETSCAPE_PLUGIN_METADATA_CACHE)
    updatePersistentMetadataCache();
#endif

    m_registeredMIMETypes.clear();

    // Register plug-in MIME types
    PluginSet::const_iterator end = m_plugins.end();
    for (PluginSet::const_iterator it = m_plugins.begin(); it != end; ++it) {
        // Get MIME types
        MIMEToDescriptionsMap::const_iterator map_it = (*it)->mimeToDescriptions().begin();
        MIMEToDescriptionsMap::const_iterator map_end = (*it)->mimeToDescriptions().end();
        for (; map_it != map_end; ++map_it)
            m_registeredMIMETypes.add(map_it->first);
    }

    return true;
}
Ejemplo n.º 20
0
void* workerThread(void* args)
{
  int client_sd = *((int*)args);
  int tid = pthread_self();

  //debug
  printf("%sAccepted client_sd: %d, tid: %d%s\n", BG_GREEN, client_sd, tid, DEFAULT);

  // Flags for the loop
  int server_sd;
  int server_sd_reusable = 0;
  int server_response_has_no_body;
  int is_case_4;
  int file_already_cached;

  while(1)
  {
    // Initialize flags
    server_response_has_no_body = 0;
    is_case_4 = 0;
    file_already_cached = 0;

    // Read HTTP Request from the client
    char clientRequest[MAX_REQUEST_SIZE];
    strcpy(clientRequest, "");
    int bytesReceived = recv(client_sd, clientRequest, sizeof(clientRequest), 0);
    if(bytesReceived < 0)
    {
      printf("%sreceive error: %s (Errno:%d)%s\n",BG_RED, strerror(errno), errno, DEFAULT);
      pthread_exit(0);
    }
    else if (bytesReceived == 0)
    {
      printf("%stid %d: Client closed the connection. %s\n", BG_RED, tid, DEFAULT);
      pthread_exit(0);
    }

    //debug
    printf("%s=== clientRequest ===%s\n", BG_YELLOW, DEFAULT);
    printf("/%s%s%s/\n",BG_BLUE, clientRequest, DEFAULT);
    printf("%s=== End of clientRequest ===%s\n", BG_YELLOW, DEFAULT);

    // Parse the HTTP Request to struct requestAttributes
    struct requestAttributes clientRequestAttributes = parseRequestMessage(clientRequest);

    printf("%sGOOGLE ANALYTICS%s\n", BG_RED, DEFAULT);
    // If server_sd can be reused, reuse it
    // Else, establish a connection to server
    if (server_sd_reusable)
      printf("Server sd is reusable. Reuse server_sd: /%s%d%s/ now. \n", BG_PURPLE, server_sd, DEFAULT);
    else
      server_sd = connectToServer(clientRequestAttributes.Host, clientRequestAttributes.port);
    server_sd_reusable = 1;

    char buf[MAX_REQUEST_SIZE];
    strcpy(buf, clientRequest);

    //debug
    printRequestAttributes(&clientRequestAttributes);

    // If the method is not GET, simply ignore it
    if (clientRequestAttributes.methodNotGET)
    {
      printf("%sIgnored a non-GET request.%s\n", BG_PURPLE, DEFAULT);
      continue;
    }

    // If the file type is not the ones that need caching,
    // simply forwards the request to the web server
    if (!clientRequestAttributes.typeNeedsCaching)
    {
      printf("%sThe request file type does not need caching. Simply forward the request to server now.%s\n", BG_PURPLE, DEFAULT);
      int byteSent = send(server_sd, buf, strlen(buf), MSG_NOSIGNAL);
      printf("Sent /%s%d%s/ bytes to the server. \n", BG_PURPLE, byteSent, DEFAULT);
      if (byteSent < 0)
      {
        printf("%sForward HTTP Request Error%s\n", BG_RED, DEFAULT);
        continue;
      }
    }
    else
    {
      // If the file is not cached in MYPROXY,
      // simply forwards it to the web server
      if (getFileModificationTime(clientRequestAttributes.URL) == -1)
      {
        printf("%sThe file is not cached on the proxy. Simply forward the request to server now. %s\n", BG_PURPLE, DEFAULT);
        int byteSent = send(server_sd, buf, strlen(buf), MSG_NOSIGNAL);
        if (byteSent < 0)
        {
          printf("%sForward HTTP Request Error%s\n", BG_RED, DEFAULT);
          continue;
        }
      }
      else
      {
        file_already_cached = 1;

        // Here goes the four cases
        int caseNumber;
        if (clientRequestAttributes.noCache)
        {
          if (clientRequestAttributes.IMS == 0)
            caseNumber = 3;
          else
            caseNumber = 4;
        }
        else
        {
          if (clientRequestAttributes.IMS == 0)
            caseNumber = 1;
          else
            caseNumber = 2;
        }

        //debug
        printf("%scaseNumber is: %d%s\n", BG_PURPLE, caseNumber, DEFAULT);

        // didn't use switch since I fear to mess up
        // the break in switch with the break in while
        if (caseNumber == 1)
        {
          // Case 1:
          // Proxy directly respond the client with the cache
          if (respondCache(clientRequestAttributes.URL, client_sd) == -1)
            break;

          goto oneLoopisDone;
        }

        if (caseNumber == 2)
        {
          // Case 2:
          // If IMS is later than LMT of the cached web object,
          // just respond 304
          // else, respond the client with 200 and the web object
          if (clientRequestAttributes.IMS > getFileModificationTime(clientRequestAttributes.URL))
          {
            char block[512];
            sprintf(block, "HTTP/1.1 304 Not Modified\r\n\r\n");
            if (send(client_sd, block, strlen(block), MSG_NOSIGNAL) <= 0)
              break;
            server_response_has_no_body = 1;
          }
          else
            if (respondCache(clientRequestAttributes.URL, client_sd) == -1)
              break;

          goto oneLoopisDone;
        }

        if (caseNumber == 3)
        {
          // Case 3:
          // Add If-Modified-Since: *LMT* header Line to the client Request
          // and then forward it to server
          time_t LMT = getFileModificationTime(clientRequestAttributes.URL);
          char timeString[50];
          getTimeStringfromRawTime(timeString, LMT);
          char* headerEnding = strstr(buf, "\r\n\r\n");
          *headerEnding = '\0';
          sprintf(headerEnding, "\r\nIf-Modified-Since: %s\r\n\r\n", timeString);

          //debug
          printf("%s=== case 3 buf ===%s\n", BG_YELLOW, DEFAULT);
          printf("/%s%s%s/\n", BG_BLUE, buf, DEFAULT);
          printf("%s=== End of case 3 buf ===%s\n", BG_YELLOW, DEFAULT);

          int byteSent = send(server_sd, buf, strlen(buf), MSG_NOSIGNAL);
          if (byteSent < 0)
          {
            printf("%sForward HTTP Request Error%s\n", BG_RED, DEFAULT);
            continue;
          }
        }

        if (caseNumber == 4)
        {
          // Case 4:
          // If IMS is later than LMT of the cached web object,
          // simply forwards it to the web server
          // Else, edit If-Modified-Since: ... header Line of the client request
          // edit the date to LMT
          // and then forward it to the web server
          is_case_4 = 1;

          time_t LMT = getFileModificationTime(clientRequestAttributes.URL);
          if (clientRequestAttributes.IMS < LMT)
          {
            char* pointerToIMS = strstr(buf, "If-Modified-Since");
            char* pointerToLatterPart = strstr(pointerToIMS, "\r\n");
            char latterPart[MAX_REQUEST_SIZE];
            strcpy(latterPart, pointerToLatterPart);
            pointerToIMS+=19; // Maybe problematic?
            *pointerToIMS = '\0';
            char timeString[50];
            getTimeStringfromRawTime(timeString, LMT);
            strcat(buf, timeString);
            strcat(buf, latterPart);

            //debug
            printf("%s=== case 4 buf ===%s\n", BG_YELLOW, DEFAULT);
            printf("/%s%s%s/\n", BG_BLUE, buf, DEFAULT);
            printf("%s=== End of case 4 buf ===%s\n", BG_YELLOW, DEFAULT);
          }

          int byteSent = send(server_sd, buf, strlen(buf), MSG_NOSIGNAL);
          if (byteSent < 0)
          {
            printf("%sForward HTTP Request Error%s\n", BG_RED, DEFAULT);
            continue;
          }
        }
      }
    }

    // Now receive server's HTTP Response's header
    char receiveBuffer[MAX_RESPONSE_SIZE];
    memset(receiveBuffer, 0, sizeof(receiveBuffer));
    char* receiveBufferPtr = receiveBuffer;

    printf("%sWaiting for the server's response...%s\n", BG_PURPLE, DEFAULT);

    // Receive byte by byte until an \r\n\r\n is found
    while(1)
    {
      bytesReceived = recv(server_sd, receiveBufferPtr, 1, 0);
      if (bytesReceived < 0)
      {
        printf("%sreceive HTTP response error%s\n", BG_RED, DEFAULT);
        break;
      }

      //debug
      else if (bytesReceived == 0)
      {
        printf("%sServer Closed the connection%s\n", BG_RED, DEFAULT);
        break; // Maybe problematic
      }
      else
      {
        //printf("%sReceived one byte%s ", BG_PURPLE, DEFAULT);

        if (strstr(receiveBuffer, "\r\n\r\n") != NULL)
        break;
        receiveBufferPtr++;
      }
    }
    receiveBufferPtr++;
    *receiveBufferPtr = '\0';

    //debug
    printf("\n%s=== server's response's header ===%s\n", BG_YELLOW, DEFAULT);
    printf("/%s%s%s/\n", BG_BLUE, receiveBuffer, DEFAULT);
    printf("%s=== End of server's response's header ===%s\n", BG_YELLOW, DEFAULT);

    // parse server's response's header
    struct responseAttributes serverResponseAttributes = parseResponseHeader(receiveBuffer);

    printResponseAttributes(&serverResponseAttributes);


    if (serverResponseAttributes.contentLength == 0 && serverResponseAttributes.isChunked == 0)
      server_response_has_no_body = 1;

    // 200 case
    if (serverResponseAttributes.statusCode == 200)
    {
      // If the file type needs caching, then cache it
      if (clientRequestAttributes.typeNeedsCaching)
      {
        if (cacheServerResponse(receiveBuffer, clientRequestAttributes.URL, server_sd, client_sd, server_response_has_no_body) == -1)
        {
          printf("%scache Error%s\n", BG_RED, DEFAULT);
          break;
        }
      }
      // Else, simply forward the response
      else
      {
        if (forwardServerResponse(receiveBuffer, server_sd, client_sd, server_response_has_no_body) == -1)
        {
          printf("%sforward Error%s\n", BG_RED, DEFAULT);
          break;
        }
      }

      printf("%sok here?2%s\n", FG_RED, DEFAULT);
    }
    // 304 case
    else if (serverResponseAttributes.statusCode == 304)
    {
      if (is_case_4)
      {
        if (respondCache(clientRequestAttributes.URL, client_sd) == -1)
        {
          printf("%srespond Error%s\n", BG_RED, DEFAULT);
          break;
        }
        goto forwardBackComplete;
      }
      else
      {
        if (forwardServerResponse(receiveBuffer, server_sd, client_sd, server_response_has_no_body) == -1)
        {
          printf("%sforward Error%s\n", BG_RED, DEFAULT);
          break;
        }
      }
    }
    // Status code is otherwise case
    else
    {
      if (forwardServerResponse(receiveBuffer, server_sd, client_sd, server_response_has_no_body) == -1)
      {
        printf("%sforward Error%s\n", BG_RED, DEFAULT);
        break;
      }
    }


    forwardBackComplete:
    oneLoopisDone:

    if (serverResponseAttributes.serverClose)
    {
      printf("%sThe server's response has Connection: close. Close server_sd now. %s\n", BG_PURPLE, DEFAULT);
      server_sd_reusable = 0;
      close(server_sd);
    }

    // This part is a workaround for the mysterious phenomenon
    // that the server_sd, after a c->p->s->p->c loop, cannot be reused
    // even though server did not respond "Connection: close" or likewise
    // Here call recv() once to test if server closed the connection at its side
    // if server did, close the server_sd
    char testByte;
    bytesReceived = recv(server_sd, &testByte, 1, MSG_PEEK | MSG_DONTWAIT);
    if (bytesReceived == 0)
    {
      printf("%sThe server silently closed the Connection. Close server_sd now. %s\n", BG_PURPLE, DEFAULT);
      server_sd_reusable = 0;
      close(server_sd);
    }

    if (server_response_has_no_body)
      break;

    if (clientRequestAttributes.clientClose)
      break;

    printf("%sOne Loop(c->p->s->p->c) is done.%s\n", BG_PURPLE, DEFAULT);

  }
  close(server_sd);
  close(client_sd);

  pthread_exit(0);
}
Ejemplo n.º 21
0
double SQLiteFileSystem::databaseModificationTime(const String& fileName)
{
    time_t time;
    return getFileModificationTime(fileName, time) ? time : 0;
}
Ejemplo n.º 22
0
bool CurlCacheEntry::parseResponseHeaders(ResourceResponse& response)
{
    double fileTime;
    time_t fileModificationDate;

    if (getFileModificationTime(m_headerFilename, fileModificationDate)) {
        fileTime = difftime(fileModificationDate, 0);
        fileTime *= 1000.0;
    } else
        fileTime = currentTimeMS(); // GMT

    if (response.cacheControlContainsNoCache() || response.cacheControlContainsNoStore())
        return false;


    double maxAge = 0;
    bool maxAgeIsValid = false;

    if (response.cacheControlContainsMustRevalidate())
        maxAge = 0;
    else {
        maxAge = response.cacheControlMaxAge();
        if (std::isnan(maxAge))
            maxAge = 0;
        else
            maxAgeIsValid = true;
    }

    if (!response.hasCacheValidatorFields())
        return false;


    double lastModificationDate = 0;
    double responseDate = 0;
    double expirationDate = 0;

    lastModificationDate = response.lastModified();
    if (std::isnan(lastModificationDate))
        lastModificationDate = 0;

    responseDate = response.date();
    if (std::isnan(responseDate))
        responseDate = 0;

    expirationDate = response.expires();
    if (std::isnan(expirationDate))
        expirationDate = 0;


    if (maxAgeIsValid) {
        // when both the cache entry and the response contain max-age, the lesser one takes priority
        double expires = fileTime + maxAge * 1000;
        if (m_expireDate == -1 || m_expireDate > expires)
            m_expireDate = expires;
    } else if (responseDate > 0 && expirationDate >= responseDate)
        m_expireDate = fileTime + (expirationDate - responseDate);

    // if there were no lifetime information
    if (m_expireDate == -1) {
        if (lastModificationDate > 0)
            m_expireDate = fileTime + (fileTime - lastModificationDate) * 0.1;
        else
            m_expireDate = 0;
    }

    String etag = response.httpHeaderField("ETag");
    if (!etag.isNull())
        m_requestHeaders.set("If-None-Match", etag);

    String lastModified = response.httpHeaderField("Last-Modified");
    if (!lastModified.isNull())
        m_requestHeaders.set("If-Modified-Since", lastModified);

    if (etag.isNull() && lastModified.isNull())
        return false;

    m_headerInMemory = true;
    return true;
}