void SuiteMulticast::Receiver() { iPortLock.Wait(); SocketUdpMulticast recv(0, Endpoint(iPort, kMulticastAddress)); iPort = recv.Port(); iPortLock.Signal(); iSender.Signal(); // signal ready to begin receiving Bwh buf(kBufBytes); Brn exp = iExp.Split(4); while(1) { recv.Receive(buf); TUint num = *((TUint32*)buf.Ptr()); if(num == kQuit) { break; } Brn exp2 = exp.Split(0, num); Brn buf2 = buf.Split(4); TEST(buf2 == exp2); iSender.Signal(); } iSender.Signal(); }
void DviSessionLpec::Unsubscribe() { AutoMutex a(iSubscriptionLock); Brn cmd = Ascii::Trim(iParser.Remaining()); if (cmd.Bytes() == 0) { for (TUint i=0; i<iSubscriptions.size(); i++) { DoUnsubscribe(0); } return; } try { const TUint lpecSid = Ascii::Uint(cmd); for (TUint i=0; i<iSubscriptions.size(); i++) { if (iSubscriptions[i].LpecSid() == lpecSid) { DoUnsubscribe(i); return; } } ReportError(LpecError::kSubscriptionNotFound); } catch (AsciiError&) { // not a sid, fall through to below to check for device/service } AutoMutex b(iDeviceLock); ParseDeviceAndService(); for (TUint i=0; i<iSubscriptions.size(); i++) { if (iSubscriptions[i].Matches(*iTargetDevice, *iTargetService)) { DoUnsubscribe(i); return; } } ReportError(LpecError::kServiceNotSubscribed); }
void DviDevice::SetAttribute(const TChar* aKey, const TChar* aValue) { Brn key(aKey); Parser parser(key); Brn name = parser.Next('.'); aKey += name.Bytes() + 1; // assume keys starting 'Test' are a special case which can be updated at any time if (strlen(aKey) < 4 || strncmp(aKey, "Test", 4) != 0) { ASSERT(iEnabled == eDisabled); } if (name == Brn("Core")) { static const char* longPollEnable = "LongPollEnable"; if (iProviderSubscriptionLongPoll == NULL && strncmp(aKey, longPollEnable, sizeof(longPollEnable)-1) == 0) { iProviderSubscriptionLongPoll = new DviProviderSubscriptionLongPoll(*this); ConfigChanged(); } } else { for (TUint i=0; i<(TUint)iProtocols.size(); i++) { IDvProtocol* protocol = iProtocols[i]; if (protocol->ProtocolName() == name) { protocol->SetAttribute(aKey, aValue); ConfigChanged(); break; } } } }
void DviSessionUpnp::ParseRequestUri(const Brx& aUrlTail, DviDevice** aDevice, DviService** aService) { Parser parser(iReaderRequest->Uri()); Brn tmp = parser.Next('/'); if (tmp.Bytes() > 0) { Error(HttpStatus::kPreconditionFailed); } Brn udn = parser.Next('/'); DviDevice* device = DviDeviceMap::Find(udn); *aDevice = device; if (device == NULL) { Error(HttpStatus::kPreconditionFailed); } Brn serviceName = parser.Next('/'); if (parser.Remaining() != aUrlTail) { Error(HttpStatus::kPreconditionFailed); } const TUint count = device->ServiceCount(); for (TUint i=0; i<count; i++) { DviService& service = device->Service(i); if (service.ServiceType().PathUpnp() == serviceName) { *aService = &service; break; } } }
Brn ReaderUntil::ReadProtocol(TUint aBytes) { ASSERT(aBytes <= iMaxBytes); TByte* start = Ptr() + iOffset; TByte* p = start; if (aBytes <= iBytes - iOffset) { iOffset += aBytes; if (iOffset == iBytes) { iBytes = 0; iOffset = 0; } return Brn(start, aBytes); } if (iBytes > 0) { iBytes -= iOffset; start = Ptr(); (void)memmove(start, start + iOffset, iBytes); p = start + iBytes; iOffset = 0; aBytes -= iBytes; } TUint remaining = aBytes; while (remaining > 0) { Brn buf = iReader.Read(remaining); (void)memcpy(p, buf.Ptr(), buf.Bytes()); p += buf.Bytes(); } iBytes = 0; iOffset = 0; return Brn(start, (TUint)(p - start)); }
void DviProtocolUpnp::GetAttribute(const TChar* aKey, const TChar** aValue) const { *aValue = iAttributeMap.Get(aKey); if (*aValue == NULL) { Brn key(aKey); static const Brn kServicePrefix("Service."); if (key.BeginsWith(kServicePrefix)) { Brn pathUpnp = key.Split(kServicePrefix.Bytes()); const TUint count = iDevice.ServiceCount(); for (TUint i=0; i<count; i++) { DviService& service = iDevice.Service(i); Bws<128> name(service.ServiceType().Domain()); const TUint bytes = name.Bytes(); for (TUint j=0; j<bytes; j++) { if (name[j] == '.') { name[j] = '-'; } } name.Append('.'); name.Append(service.ServiceType().Name()); if (name == pathUpnp) { *aValue = (const TChar*)(service.ServiceType().VersionBuf().Ptr()); return; } } } } }
void HttpHeaderContentType::Process(const Brx& aValue) { Parser parser(aValue); try { Brn type = parser.Next(';'); Parser parser2(type); // get first word of the type iType.Replace(parser2.Next()); SetReceived(); } catch (BufferOverflow&) { return; } Brn key; Brn value; for (;;) { key.Set(parser.Next('=')); if (key.Bytes() == 0) { return; } value.Set(parser.Next()); Process(key, value); } }
void ReaderHttpChunked::Read() { for (;;) { Brn chunkSizeBuf = iReader.ReadUntil(Ascii::kLf); Parser parser(chunkSizeBuf); Brn trimmed = parser.Next(Ascii::kCr); if (trimmed.Bytes() == 0) { continue; } TUint chunkSize; try { chunkSize = Ascii::UintHex(trimmed); } catch (AsciiError&) { THROW(ReaderError); } if (chunkSize == 0) { break; } iEntity.Grow(iEntity.Bytes() + chunkSize); while (chunkSize > 0) { TUint bytes = (chunkSize<4096? chunkSize : 4096); iEntity.Append(iReader.Read(bytes)); chunkSize -= bytes; } } }
void DeviceBasic::WriteResource(const Brx& aUriTail, TIpAddress /*aInterface*/, std::vector<char*>& /*aLanguageList*/, IResourceWriter& aResourceWriter) { const Brn kIndexFile("index.html"); Bwh filePath(iConfigDir); Brn file; if (aUriTail.Bytes() == 0) { file.Set(kIndexFile); } else { file.Set(aUriTail); } const TByte sep = #ifdef _WIN32 '\\'; #else '/'; #endif filePath.Grow(filePath.Bytes() + 1 + file.Bytes()+1); filePath.Append(sep); filePath.Append(file); filePath.PtrZ(); const char* path = (const char*)filePath.Ptr(); FILE* fd = fopen(path, "rb"); if (fd == NULL) { return; } static const TUint kMaxReadSize = 4096; struct stat fileStats; (void)stat(path, &fileStats); TUint bytes = (TUint)fileStats.st_size; const char* mime = NULL; for (TUint i=filePath.Bytes()-1; i>0; i--) { if (filePath[i] == '/' || filePath[i] == '\\') { break; } if (filePath[i] == '.') { const char* ext = (const char*)filePath.Split(i+1, filePath.Bytes()-i-1).Ptr(); if (strcmp(ext, "html") == 0 || strcmp(ext, "htm") == 0) { mime = kOhNetMimeTypeHtml; } break; } } aResourceWriter.WriteResourceBegin(bytes, mime); do { TByte buf[kMaxReadSize]; TUint size = (bytes<kMaxReadSize? bytes : kMaxReadSize); size_t records_read = fread(buf, size, 1, fd); ASSERT(records_read == 1); aResourceWriter.WriteResource(buf, size); bytes -= size; } while (bytes > 0); aResourceWriter.WriteResourceEnd(); (void)fclose(fd); }
void XmlFetch::Read() { iDechunker.ReadFlush(); ReaderHttpResponse readerResponse(iCpStack.Env(), iReaderUntil); HttpHeaderContentLength headerContentLength; HttpHeaderTransferEncoding headerTransferEncoding; readerResponse.AddHeader(headerContentLength); readerResponse.AddHeader(headerTransferEncoding); readerResponse.Read(kResponseTimeoutMs); const HttpStatus& status = readerResponse.Status(); if (status != HttpStatus::kOk) { LOG2(kXmlFetch, kError, "XmlFetch::Read, http error %u ", status.Code()); LOG2(kXmlFetch, kError, status.Reason()); LOG2(kXmlFetch, kError, "\n"); SetError(Error::eHttp, status.Code(), status.Reason()); THROW(HttpError); } if (iCheckContactable) { iContactable = true; return; } WriterBwh writer(1024); static const TUint kMaxReadBytes = 4 * 1024; if (headerTransferEncoding.IsChunked()) { iDechunker.SetChunked(true); for (;;) { Brn buf = iDechunker.Read(kMaxReadBytes); writer.Write(buf); if (buf.Bytes() == 0) { // end of stream break; } } } else { TUint remaining = headerContentLength.ContentLength(); if (remaining == 0) { // no content length - read until connection closed by server try { for (;;) { writer.Write(iReaderUntil.Read(kMaxReadBytes)); } } catch (ReaderError&) { } } else { do { Brn buf = iReaderUntil.Read(kMaxReadBytes); remaining -= buf.Bytes(); writer.Write(buf); } while (remaining > 0); } } writer.TransferTo(iXml); }
void DviProtocolUpnpServiceXmlWriter::GetRelatedVariableName(Bwh& aName, const Brx& aActionName, const Brx& aParameterName) { static const Brn prefix("A_ARG_TYPE_"); const TUint len = prefix.Bytes() + aActionName.Bytes() + 1 + aParameterName.Bytes(); aName.Grow(len); aName.Append(prefix); aName.Append(aActionName); aName.Append('_'); aName.Append(aParameterName); }
void ReaderBinary::ReadReplace(TUint aBytes, Bwx& aBuffer) { ASSERT(aBytes <= aBuffer.MaxBytes()); aBuffer.SetBytes(0); while (aBytes > 0) { Brn buf = iReader.Read(aBytes); aBuffer.Append(buf); aBytes -= buf.Bytes(); } }
void ReaderBinary::Read(TUint aBytes) { ASSERT(aBytes <= iBuf.MaxBytes()); iBuf.SetBytes(0); while (aBytes > 0) { Brn buf = iReader.Read(aBytes); iBuf.Append(buf); aBytes -= buf.Bytes(); } }
void DviSessionLpec::InvocationReadBinary(const TChar* /*aName*/, Brh& aData) { (void)iParser.Next(Lpec::kArgumentDelimiter); Brn val = iParser.NextNoTrim(Lpec::kArgumentDelimiter); if (val.Bytes() != 0) { Bwh writable(val.Bytes()+1); writable.Append(val); Converter::FromBase64(writable); writable.TransferTo(aData); } }
void WsHeaderKey80::Process(const Brx& aValue) { SetReceived(); Brn suffix("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); Brn val = Ascii::Trim(aValue); Bwh buf(val.Bytes() + suffix.Bytes() + 1); buf.Append(val); buf.Append(suffix); buf.PtrZ(); buf.TransferTo(iKey); }
void DviSessionLpec::InvocationReadString(const TChar* /*aName*/, Brhz& aString) { (void)iParser.Next(Lpec::kArgumentDelimiter); Brn val = iParser.NextNoTrim(Lpec::kArgumentDelimiter); Bwh writable(val.Bytes()+1); if (val.Bytes()) { writable.Append(val); Converter::FromXmlEscaped(writable); } writable.PtrZ(); writable.TransferTo(aString); }
void CpTopology2Product::EventProductInitialEvent() { Functor functorRoom = MakeFunctor(*this, &CpTopology2Product::EventProductRoomChanged); Functor functorName = MakeFunctor(*this, &CpTopology2Product::EventProductNameChanged); Functor functorStandby = MakeFunctor(*this, &CpTopology2Product::EventProductStandbyChanged); Functor functorSourceIndex = MakeFunctor(*this, &CpTopology2Product::EventProductSourceIndexChanged); Functor functorSourceXml = MakeFunctor(*this, &CpTopology2Product::EventProductSourceXmlChanged); iServiceProduct->SetPropertyProductRoomChanged(functorRoom); iServiceProduct->SetPropertyProductNameChanged(functorName); iServiceProduct->SetPropertyStandbyChanged(functorStandby); iServiceProduct->SetPropertySourceIndexChanged(functorSourceIndex); iServiceProduct->SetPropertySourceXmlChanged(functorSourceXml); TBool hasVolumeControl = false; Brhz attributes; iServiceProduct->PropertyAttributes(attributes); Parser parser(attributes); for (;;) { Brn attribute = parser.Next(); if (attribute.Bytes() == 0) { break; } if (attribute == Brn("Volume")) { hasVolumeControl = true; break; } } Brhz room; Brhz name; TUint sourceIndex; TBool standby; Brhz xml; iServiceProduct->PropertyProductRoom(room); iServiceProduct->PropertyProductName(name); iServiceProduct->PropertySourceIndex(sourceIndex); iServiceProduct->PropertyStandby(standby); iServiceProduct->PropertySourceXml(xml); iGroup = new CpTopology2Group(iDevice, *this, standby, room, name, sourceIndex, hasVolumeControl); ProcessSourceXml(xml, true); iHandler.GroupAdded(*iGroup); }
void DviDeviceMap::WriteResource(const Brx& aUriTail, TIpAddress aInterface, std::vector<char*>& aLanguageList, IResourceWriter& aResourceWriter) { AutoMutex a(iLock); Parser parser(aUriTail); (void)parser.Next('/'); // skip leading slash Brn dir = parser.Next('/'); if (dir.Bytes() > 0) { Map::iterator it = iMap.find(dir); if (it != iMap.end()) { it->second->WriteResource(parser.Remaining(), aInterface, aLanguageList, aResourceWriter); } } }
void XmlFetch::Read(SocketTcpClient& aSocket) { Srd readBuffer(kRwBufferLength, aSocket); ReaderHttpResponse readerResponse(iCpStack.Env(), readBuffer); HttpHeaderContentLength headerContentLength; HttpHeaderTransferEncoding headerTransferEncoding; readerResponse.AddHeader(headerContentLength); readerResponse.AddHeader(headerTransferEncoding); readerResponse.Read(kResponseTimeoutMs); const HttpStatus& status = readerResponse.Status(); if (status != HttpStatus::kOk) { LOG2(kXmlFetch, kError, "XmlFetch::Read, http error %u ", status.Code()); LOG2(kXmlFetch, kError, status.Reason()); LOG2(kXmlFetch, kError, "\n"); SetError(Error::eHttp, status.Code(), status.Reason()); THROW(HttpError); } if (headerTransferEncoding.IsChunked()) { ReaderHttpChunked dechunker(readBuffer); dechunker.Read(); dechunker.TransferTo(iXml); } else { TUint remaining = headerContentLength.ContentLength(); if (remaining == 0) { // no content length - read until connection closed by server try { for (;;) { Brn buf = readBuffer.Read(kRwBufferLength); iXml.Grow(iXml.Bytes() + kRwBufferLength); iXml.Append(buf); } } catch (ReaderError&) { Brn snaffle = readBuffer.Snaffle(); iXml.Grow(iXml.Bytes() + snaffle.Bytes()); iXml.Append(snaffle); } } else { while (remaining > 0) { TInt readBytes = (remaining > kRwBufferLength ? kRwBufferLength : remaining); Brn buf = readBuffer.Read(readBytes); iXml.Grow(iXml.Bytes() + readBytes); iXml.Append(buf); remaining -= readBytes; } } } }
void SsdpHeaderUsn::Process(const Brx& aValue) { SetReceived(); Parser parser(aValue); Brn prefix = parser.Next(':'); if (prefix != kUuid) { THROW(HttpError); } Brn uuid = parser.Next(':'); if (uuid.Bytes() > kMaxUuidBytes) { THROW(HttpError); } iUuid.Replace(uuid); if (parser.Next(kUuidSeparator).Bytes() != 0) { // double colon separator THROW(HttpError); } Brn value = parser.Remaining(); if (value.Bytes() == 0) { iTarget = eSsdpUuid; return; } if (value == kUpnpRoot) { iTarget = eSsdpRoot; return; } Brn type = parser.Next(':'); if (type == kMsearchUrn) { Brn domain = parser.Next(':'); Brn kind = parser.Next(':'); Brn type = parser.Next(':'); if (domain.Bytes() > kMaxDomainBytes) { THROW(HttpError); } Ssdp::UpnpDomainToCanonical(domain, iDomain); if (type.Bytes() > kMaxTypeBytes) { THROW(HttpError); } iType.Replace(type); try { iVersion = Ascii::Uint(parser.Remaining()); } catch (AsciiError&) { THROW(HttpError); } if (kind == kMsearchDevice) { iTarget = eSsdpDeviceType; return; } if (kind == kMsearchService) { iTarget = eSsdpServiceType; return; } } THROW(HttpError); }
void ReaderHttpRequest::Read(TUint aTimeoutMs) { TUint count = 0; iMethod = 0; ResetHeaders(); for (;;) { Brn line; { Timer timer(MakeFunctor(*this, &ReaderHttpRequest::ReadTimeout)); if (aTimeoutMs > 0) { timer.FireIn(aTimeoutMs); } line.Set(Ascii::Trim(iReader.ReadUntil(Ascii::kLf))); timer.Cancel(); } // LOG(kHttp, "HTTP Read Request "); // LOG(kHttp, line); // LOG(kHttp, "\n"); TUint bytes = line.Bytes(); if (!bytes) { if (count == 0) { continue; // a blank line before first header - ignore (RFC 2616 section 4.1) } if (iMethod == 0) { THROW(HttpError); } return; } if (Ascii::IsWhitespace(line[0])) { continue; // a line starting with spaces is a continuation line } Parser parser(line); if (count == 0) { // method Brn method = parser.Next(); Brn uri = parser.Next(); Brn version = Ascii::Trim(parser.Remaining()); ProcessMethod(method, uri, version); } else { // header Brn field = parser.Next(':'); Brn value = Ascii::Trim(parser.Remaining()); ProcessHeader(field, value); } count++; } }
TBool CpiDeviceUpnp::UdnMatches(const Brx& aFound, const Brx& aTarget) { const Brn udnPrefix("uuid:"); Brn udn(aFound); if (udn.Bytes() <= udnPrefix.Bytes()) { THROW(XmlError); } Brn prefix = udn.Split(0, udnPrefix.Bytes()); if (prefix != udnPrefix) { THROW(XmlError); } udn.Set(udn.Split(udnPrefix.Bytes(), udn.Bytes() - udnPrefix.Bytes())); return (udn == aTarget); }
TBool CpiDeviceUpnp::GetAttribute(const char* aKey, Brh& aValue) const { Brn key(aKey); Parser parser(key); if (parser.Next('.') == Brn("Upnp")) { Brn property = parser.Remaining(); if (property == Brn("Location")) { aValue.Set(iLocation); return (true); } if (property == Brn("DeviceXml")) { aValue.Set(iXml); return (true); } const DeviceXml* device = iDeviceXml; if (parser.Next('.') == Brn("Root")) { device = &iDeviceXmlDocument->Root(); property.Set(parser.Remaining()); } try { if (property == Brn("FriendlyName")) { device->GetFriendlyName(aValue); return (true); } if (property == Brn("PresentationUrl")) { device->GetPresentationUrl(aValue); return (true); } Parser parser(property); Brn token = parser.Next('.'); if (token == Brn("Service")) { aValue.Set(device->ServiceVersion(parser.Remaining())); return (true); } } catch (XmlError&) { } } return (false); }
void HeaderAcceptLanguage::Process(const Brx& aValue) { SetReceived(); ClearLanguageList(); iLanguages.Set(aValue); std::vector<PrioritisedLanguage> prioritisedList; Parser parser(iLanguages); while (parser.Remaining().Bytes() > 0) { Brn langBuf = parser.Next(','); Parser parser2(langBuf); Brn lang = parser2.Next(';'); parser2.Set(parser2.Remaining()); Brn qualityBuf = parser2.Next('='); if (qualityBuf.Bytes() > 0) { qualityBuf.Set(parser2.Remaining()); } TUint quality = ParseQualityValue(qualityBuf); PrioritisedLanguage prioritisedLang; prioritisedLang.iLanguage = (char*)malloc(lang.Bytes()+1); (void)memcpy(prioritisedLang.iLanguage, lang.Ptr(), lang.Bytes()); prioritisedLang.iLanguage[lang.Bytes()] = '\0'; prioritisedLang.iPriority = quality; AddPrioritisedLanguage(prioritisedList, prioritisedLang); } for (TUint i=0; i<(TUint)prioritisedList.size(); i++) { iLanguageList.push_back(prioritisedList[i].iLanguage); } }
void DviProtocolUpnp::WriteResource(const Brx& aUriTail, TIpAddress aAdapter, std::vector<char*>& aLanguageList, IResourceWriter& aResourceWriter) { if (aUriTail == kDeviceXmlName) { Brh xml; Brn xmlBuf; AutoMutex _(iLock); const TInt index = FindListenerForInterface(aAdapter); if (index == -1) { return; } if (iDevice.IsRoot()) { const Brx& cachedXml = iAdapters[index]->DeviceXml(); if (cachedXml.Bytes() > 0) { xmlBuf.Set(cachedXml); } } if (xmlBuf.Bytes() == 0) { GetDeviceXml(xml, aAdapter); if (iDevice.IsRoot()) { iAdapters[index]->SetDeviceXml(xml); xmlBuf.Set(iAdapters[index]->DeviceXml()); } else { xmlBuf.Set(xml); } } aResourceWriter.WriteResourceBegin(xmlBuf.Bytes(), kOhNetMimeTypeXml); aResourceWriter.WriteResource(xmlBuf.Ptr(), xmlBuf.Bytes()); aResourceWriter.WriteResourceEnd(); } else { Parser parser(aUriTail); Brn buf = parser.Next('/'); Brn rem = parser.Remaining(); if (buf == DviDevice::kResourceDir) { IResourceManager* resMgr = iDevice.ResourceManager(); if (resMgr != NULL) { resMgr->WriteResource(rem, aAdapter, aLanguageList, aResourceWriter); } } else if (rem == kServiceXmlName) { iLock.Wait(); DviService* service = 0; const TUint count = iDevice.ServiceCount(); for (TUint i=0; i<count; i++) { DviService& s = iDevice.Service(i); if (s.ServiceType().PathUpnp() == buf) { service = &s; break; } } iLock.Signal(); if (service == 0) { THROW(ReaderError); } DviProtocolUpnpServiceXmlWriter::Write(*service, *this, aResourceWriter); } } }
void DviSessionUpnp::InvocationReadBinary(const TChar* aName, Brh& aData) { try { Brn value = XmlParserBasic::Find(aName, iSoapRequest); if (value.Bytes()) { Bwh writable(value.Bytes()+1); writable.Append(value); Converter::FromBase64(writable); writable.TransferTo(aData); } } catch (XmlError&) { InvocationReportError(501, Brn("Invalid XML")); } }
void DviDevice::GetAttribute(const TChar* aKey, const TChar** aValue) const { Brn key(aKey); Parser parser(key); Brn name = parser.Next('.'); for (TUint i=0; i<(TUint)iProtocols.size(); i++) { IDvProtocol* protocol = iProtocols[i]; if (protocol->ProtocolName() == name) { aKey += name.Bytes() + 1; protocol->GetAttribute(aKey, aValue); return; } } *aValue = NULL; }
Brn ReaderText::ReadLine() { Brn line; try { line.Set(Ascii::Trim(ReadUntil(Ascii::kLf))); } catch (ReaderError&) { // treat any content following the last newline as a final line line.Set(Read(iMaxBytes)); if (line.Bytes() == 0) { throw; } } return line; }
TBool DviSessionLpec::InvocationReadBool(const TChar* /*aName*/) { (void)iParser.Next(Lpec::kArgumentDelimiter); Brn val = iParser.Next(Lpec::kArgumentDelimiter); if (Ascii::CaseInsensitiveEquals(val, Lpec::kBoolFalse) || (val.Bytes() == 1 && val[0] == '0')) { return false; } if (Ascii::CaseInsensitiveEquals(val, Lpec::kBoolTrue) || (val.Bytes() == 1 && val[0] == '1')) { return true; } ReportError(LpecError::kInvalidArgBool); return false; // never reached }
void ReaderHttpResponse::Read(TUint aTimeoutMs) { iReader.ReadFlush(); ResetHeaders(); TUint count = 0; for (;;) { Brn line; { Timer timer(MakeFunctor(*this, &ReaderHttpResponse::ReadTimeout)); if (aTimeoutMs > 0) { timer.FireIn(aTimeoutMs); } line.Set(Ascii::Trim(iReader.ReadUntil(Ascii::kLf))); timer.Cancel(); } LOG(kHttp, "HTTP Read Response "); LOG(kHttp, line); LOG(kHttp, "\n"); TUint bytes = line.Bytes(); if (!bytes) { if (count == 0) { continue; // a blank line before first header - ignore (RFC 2616 section 4.1) } return; } if (Ascii::IsWhitespace(line[0])) { continue; // a line starting with spaces is a continuation line } Parser parser(line); if (count == 0) { // status // LOG(kHttp, " status "); Brn version = parser.Next(' '); Brn code = parser.Next(' '); Brn description = Ascii::Trim(parser.Remaining()); ProcessStatus(version, code, description); } else { // header // LOG(kHttp, " header "); Brn field = parser.Next(':'); Brn value = Ascii::Trim(parser.Remaining()); ProcessHeader(field, value); } count++; } }