Exemple #1
0
	torrent_handle session::add_torrent(add_torrent_params const& params, error_code& ec)
	{
		ec.clear();
		if (string_begins_no_case("magnet:", params.url.c_str()))
		{
			add_torrent_params p(params);
			p.url.clear();
			return add_magnet_uri(*this, params.url, p, ec);
		}

		TORRENT_SYNC_CALL_RET2(torrent_handle, add_torrent, params, boost::ref(ec));
		return r;
	}
Exemple #2
0
	torrent_handle session::add_torrent(add_torrent_params const& params)
	{
		if (string_begins_no_case("magnet:", params.url.c_str()))
		{
			add_torrent_params p(params);
			p.url.clear();
			return add_magnet_uri(*this, params.url, p);
		}

		error_code ec;
		TORRENT_SYNC_CALL_RET2(torrent_handle, add_torrent, params, ec);
		if (ec) throw libtorrent_exception(ec);
		return r;
	}
Exemple #3
0
	boost::tuple<int, int> http_parser::incoming(
		buffer::const_interval recv_buffer, bool& error)
	{
		TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left());
		boost::tuple<int, int> ret(0, 0);
		int start_pos = m_recv_buffer.left();

		// early exit if there's nothing new in the receive buffer
		if (start_pos == recv_buffer.left()) return ret;
		m_recv_buffer = recv_buffer;

		if (m_state == error_state)
		{
			error = true;
			return ret;
		}

		char const* pos = recv_buffer.begin + m_recv_pos;

restart_response:

		if (m_state == read_status)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			// if we don't have a full line yet, wait.
			if (newline == recv_buffer.end)
			{
				boost::get<1>(ret) += m_recv_buffer.left() - start_pos;
				return ret;
			}

			if (newline == pos)
			{
				m_state = error_state;
				error = true;
				return ret;
			}

			char const* line_end = newline;
			if (pos != line_end && *(line_end - 1) == '\r') --line_end;

			char const* line = pos;
			++newline;
			int incoming = int(newline - pos);
			m_recv_pos += incoming;
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
			pos = newline;

			m_protocol = read_until(line, ' ', line_end);
			if (m_protocol.substr(0, 5) == "HTTP/")
			{
				m_status_code = atoi(read_until(line, ' ', line_end).c_str());
				m_server_message = read_until(line, '\r', line_end);
			}
			else
			{
				m_method = m_protocol;
				std::transform(m_method.begin(), m_method.end(), m_method.begin(), &to_lower);
				// the content length is assumed to be 0 for requests
				m_content_length = 0;
				m_protocol.clear();
				m_path = read_until(line, ' ', line_end);
				m_protocol = read_until(line, ' ', line_end);
				m_status_code = 0;
			}
			m_state = read_header;
			start_pos = pos - recv_buffer.begin;
		}

		if (m_state == read_header)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			std::string line;

			while (newline != recv_buffer.end && m_state == read_header)
			{
				// if the LF character is preceeded by a CR
				// charachter, don't copy it into the line string.
				char const* line_end = newline;
				if (pos != line_end && *(line_end - 1) == '\r') --line_end;
				line.assign(pos, line_end);
				++newline;
				m_recv_pos += newline - pos;
				pos = newline;

				std::string::size_type separator = line.find(':');
				if (separator == std::string::npos)
				{
					if (m_status_code == 100)
					{
						// for 100 Continue, we need to read another response header
						// before reading the body
						m_state = read_status;
						goto restart_response;
					}
					// this means we got a blank line,
					// the header is finished and the body
					// starts.
					m_state = read_body;
					// if this is a request (not a response)
					// we're done once we reach the end of the headers
//					if (!m_method.empty()) m_finished = true;
					// the HTTP header should always be < 2 GB
					TORRENT_ASSERT(m_recv_pos < INT_MAX);
					m_body_start_pos = int(m_recv_pos);
					break;
				}

				std::string name = line.substr(0, separator);
				std::transform(name.begin(), name.end(), name.begin(), &to_lower);
				++separator;
				// skip whitespace
				while (separator < line.size()
					&& (line[separator] == ' ' || line[separator] == '\t'))
					++separator;
				std::string value = line.substr(separator, std::string::npos);
				m_header.insert(std::make_pair(name, value));

				if (name == "content-length")
				{
					m_content_length = strtoll(value.c_str(), 0, 10);
				}
				else if (name == "content-range")
				{
					bool success = true;
					char const* ptr = value.c_str();

					// apparently some web servers do not send the "bytes"
					// in their content-range. Don't treat it as an error
					// if we can't find it, just assume the byte counters
					// start immediately
					if (string_begins_no_case("bytes ", ptr)) ptr += 6;
					char* end;
					m_range_start = strtoll(ptr, &end, 10);
					if (end == ptr) success = false;
					else if (*end != '-') success = false;
					else
					{
						ptr = end + 1;
						m_range_end = strtoll(ptr, &end, 10);
						if (end == ptr) success = false;
					}

					if (!success || m_range_end < m_range_start)
					{
						m_state = error_state;
						error = true;
						return ret;
					}
					// the http range is inclusive
					m_content_length = m_range_end - m_range_start + 1;
				}
				else if (name == "transfer-encoding")
				{
					m_chunked_encoding = string_begins_no_case("chunked", value.c_str());
				}

				TORRENT_ASSERT(m_recv_pos <= recv_buffer.left());
				newline = std::find(pos, recv_buffer.end, '\n');
			}
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
		}

		if (m_state == read_body)
		{
			int incoming = recv_buffer.end - pos;

			if (m_chunked_encoding && (m_flags & dont_parse_chunks) == 0)
			{
				if (m_cur_chunk_end == -1)
					m_cur_chunk_end = m_body_start_pos;

				while (m_cur_chunk_end <= m_recv_pos + incoming && !m_finished && incoming > 0)
				{
					size_type payload = m_cur_chunk_end - m_recv_pos;
					if (payload > 0)
					{
						TORRENT_ASSERT(payload < INT_MAX);
						m_recv_pos += payload;
						boost::get<0>(ret) += int(payload);
						incoming -= int(payload);
					}
					buffer::const_interval buf(recv_buffer.begin + m_cur_chunk_end, recv_buffer.end);
					size_type chunk_size;
					int header_size;
					if (parse_chunk_header(buf, &chunk_size, &header_size))
					{
						if (chunk_size > 0)
						{
							std::pair<size_type, size_type> chunk_range(m_cur_chunk_end + header_size
								, m_cur_chunk_end + header_size + chunk_size);
							m_chunked_ranges.push_back(chunk_range);
						}
						m_cur_chunk_end += header_size + chunk_size;
						if (chunk_size == 0)
						{
							m_finished = true;
							TORRENT_ASSERT(m_content_length < 0 || m_recv_pos - m_body_start_pos
								- m_chunk_header_size == m_content_length);
						}
						header_size -= m_partial_chunk_header;
						m_partial_chunk_header = 0;
//						fprintf(stderr, "parse_chunk_header(%d, -> %d, -> %d) -> %d\n"
//							"  incoming = %d\n  m_recv_pos = %d\n  m_cur_chunk_end = %d\n"
//							"  content-length = %d\n"
//							, buf.left(), int(chunk_size), header_size, 1, incoming, int(m_recv_pos)
//							, m_cur_chunk_end, int(m_content_length));
					}
					else
					{
						m_partial_chunk_header += incoming;
						header_size = incoming;
						
//						fprintf(stderr, "parse_chunk_header(%d, -> %d, -> %d) -> %d\n"
//							"  incoming = %d\n  m_recv_pos = %d\n  m_cur_chunk_end = %d\n"
//							"  content-length = %d\n"
//							, buf.left(), int(chunk_size), header_size, 0, incoming, int(m_recv_pos)
//							, m_cur_chunk_end, int(m_content_length));
					}
					m_chunk_header_size += header_size;
					m_recv_pos += header_size;
					boost::get<1>(ret) += header_size;
					incoming -= header_size;
				}
				if (incoming > 0)
				{
					m_recv_pos += incoming;
					boost::get<0>(ret) += incoming;
//					incoming = 0;
				}
			}
			else
			{
				size_type payload_received = m_recv_pos - m_body_start_pos + incoming;
				if (payload_received > m_content_length
					&& m_content_length >= 0)
				{
					TORRENT_ASSERT(m_content_length - m_recv_pos + m_body_start_pos < INT_MAX);
					incoming = int(m_content_length - m_recv_pos + m_body_start_pos);
				}

				TORRENT_ASSERT(incoming >= 0);
				m_recv_pos += incoming;
				boost::get<0>(ret) += incoming;
			}

			if (m_content_length >= 0
				&& !m_chunked_encoding
				&& m_recv_pos - m_body_start_pos >= m_content_length)
			{
				m_finished = true;
			}
		}
		return ret;
	}
Exemple #4
0
	void xml_parse(char* p, char* end, CallbackType callback)
	{
		for(;p != end; ++p)
		{
			char const* start = p;
			char const* val_start = 0;
			int token;
			// look for tag start
			for(; *p != '<' && p != end; ++p);

			if (p != start)
			{
				if (p != end)
				{
					TORRENT_ASSERT(*p == '<');
					*p = 0;
				}
				token = xml_string;
				callback(token, start, val_start);
				if (p != end) *p = '<';
			}

			if (p == end) break;
		
			// skip '<'
			++p;
			if (p != end && p+8 < end && string_begins_no_case("![CDATA[", p))
			{
				// CDATA. match '![CDATA['
				p += 8;
				start = p;
				while (p != end && !string_begins_no_case("]]>", p-2)) ++p;

				// parse error
				if (p == end)
				{
					token = xml_parse_error;
					start = "unexpected end of file";
					callback(token, start, val_start);
					break;
				}
			
				token = xml_string;
				char tmp = p[-2];
				p[-2] = 0;
				callback(token, start, val_start);
				p[-2] = tmp;
				continue;
			}

			// parse the name of the tag.
			for (start = p; p != end && *p != '>' && !is_space(*p); ++p);

			char* tag_name_end = p;

			// skip the attributes for now
			for (; p != end && *p != '>'; ++p);

			// parse error
			if (p == end)
			{
				token = xml_parse_error;
				start = "unexpected end of file";
				callback(token, start, val_start);
				break;
			}
			
			TORRENT_ASSERT(*p == '>');
			// save the character that terminated the tag name
			// it could be both '>' and ' '.
			char save = *tag_name_end;
			*tag_name_end = 0;

			char* tag_end = p;
			if (*start == '/')
			{
				++start;
				token = xml_end_tag;
				callback(token, start, val_start);
			}
			else if (*(p-1) == '/')
			{
				*(p-1) = 0;
				token = xml_empty_tag;
				callback(token, start, val_start);
				*(p-1) = '/';
				tag_end = p - 1;
			}
			else if (*start == '?' && *(p-1) == '?')
			{
				*(p-1) = 0;
				++start;
				token = xml_declaration_tag;
				callback(token, start, val_start);
				*(p-1) = '?';
				tag_end = p - 1;
			}
			else if (start + 5 < p && std::memcmp(start, "!--", 3) == 0 && std::memcmp(p-2, "--", 2) == 0)
			{
				start += 3;
				*(p-2) = 0;
				token = xml_comment;
				callback(token, start, val_start);
				*(p-2) = '-';
				tag_end = p - 2;
			}
			else
			{
				token = xml_start_tag;
				callback(token, start, val_start);
			}

			*tag_name_end = save;

			// parse attributes
			for (char* i = tag_name_end; i < tag_end; ++i)
			{
				// find start of attribute name
				for (; i != tag_end && is_space(*i); ++i);
				if (i == tag_end) break;
				start = i;
				// find end of attribute name
				for (; i != tag_end && *i != '=' && !is_space(*i); ++i);
				char* name_end = i;

				// look for equality sign
				for (; i != tag_end && *i != '='; ++i);

				if (i == tag_end)
				{
					token = xml_parse_error;
					val_start = 0;
					start = "garbage inside element brackets";
					callback(token, start, val_start);
					break;
				}

				++i;
				for (; i != tag_end && is_space(*i); ++i);
				// check for parse error (values must be quoted)
				if (i == tag_end || (*i != '\'' && *i != '\"'))
				{
					token = xml_parse_error;
					val_start = 0;
					start = "unquoted attribute value";
					callback(token, start, val_start);
					break;
				}
				char quote = *i;
				++i;
				val_start = i;
				for (; i != tag_end && *i != quote; ++i);
				// parse error (missing end quote)
				if (i == tag_end)
				{
					token = xml_parse_error;
					val_start = 0;
					start = "missing end quote on attribute";
					callback(token, start, val_start);
					break;
				}
				save = *i;
				*i = 0;
				*name_end = 0;
				token = xml_attribute;
				callback(token, start, val_start);
				*name_end = '=';
				*i = save;
			}
		}
	}
Exemple #5
0
	TORRENT_EXTRA_EXPORT void xml_parse(char const* p, char const* end
		, boost::function<void(int,char const*,int,char const*,int)> callback)
	{
		for(;p != end; ++p)
		{
			char const* start = p;
			int token;
			// look for tag start
			for(; p != end && *p != '<'; ++p);

			if (p != start)
			{
				token = xml_string;
				const int name_len = p - start;
				callback(token, start, name_len, nullptr, 0);
			}

			if (p == end) break;

			// skip '<'
			++p;
			if (p != end && p+8 < end && string_begins_no_case("![CDATA[", p))
			{
				// CDATA. match '![CDATA['
				p += 8;
				start = p;
				while (p != end && !string_begins_no_case("]]>", p-2)) ++p;

				// parse error
				if (p == end)
				{
					token = xml_parse_error;
					start = "unexpected end of file";
					callback(token, start, int(strlen(start)), nullptr, 0);
					break;
				}

				token = xml_string;
				const int name_len = p - start - 2;
				callback(token, start, name_len, nullptr, 0);
				continue;
			}

			// parse the name of the tag.
			for (start = p; p != end && *p != '>' && !is_space(*p); ++p);

			char const* tag_name_end = p;

			// skip the attributes for now
			for (; p != end && *p != '>'; ++p);

			// parse error
			if (p == end)
			{
				token = xml_parse_error;
				start = "unexpected end of file";
				callback(token, start, int(strlen(start)), nullptr, 0);
				break;
			}

			TORRENT_ASSERT(*p == '>');

			char const* tag_end = p;
			if (*start == '/')
			{
				++start;
				token = xml_end_tag;
				const int name_len = tag_name_end - start;
				callback(token, start, name_len, nullptr, 0);
			}
			else if (*(p-1) == '/')
			{
				token = xml_empty_tag;
				const int name_len = (std::min)(tag_name_end - start, p - start - 1);
				callback(token, start, name_len, nullptr, 0);
				tag_end = p - 1;
			}
			else if (*start == '?' && *(p-1) == '?')
			{
				++start;
				token = xml_declaration_tag;
				const int name_len = (std::min)(tag_name_end - start, p - start - 1);
				callback(token, start, name_len, nullptr, 0);
				tag_end = p - 1;
			}
			else if (start + 5 < p && std::memcmp(start, "!--", 3) == 0 && std::memcmp(p-2, "--", 2) == 0)
			{
				start += 3;
				token = xml_comment;
				const int name_len = tag_name_end - start - 2;
				callback(token, start, name_len, nullptr, 0);
				tag_end = p - 2;
				continue;
			}
			else
			{
				token = xml_start_tag;
				const int name_len = tag_name_end - start;
				callback(token, start, name_len, nullptr, 0);
			}

			// parse attributes
			for (char const* i = tag_name_end; i < tag_end; ++i)
			{
				char const* val_start = nullptr;

				// find start of attribute name
				for (; i != tag_end && is_space(*i); ++i);
				if (i == tag_end) break;
				start = i;
				// find end of attribute name
				for (; i != tag_end && *i != '=' && !is_space(*i); ++i);
				const int name_len = i - start;

				// look for equality sign
				for (; i != tag_end && *i != '='; ++i);

				// no equality sign found. Report this as xml_tag_content
				// instead of a series of key value pairs
				if (i == tag_end)
				{
					token = xml_tag_content;
					callback(token, start, i - start, nullptr, 0);
					break;
				}

				++i;
				for (; i != tag_end && is_space(*i); ++i);
				// check for parse error (values must be quoted)
				if (i == tag_end || (*i != '\'' && *i != '\"'))
				{
					token = xml_parse_error;
					start = "unquoted attribute value";
					callback(token, start, int(strlen(start)), nullptr, 0);
					break;
				}
				char quote = *i;
				++i;
				val_start = i;
				for (; i != tag_end && *i != quote; ++i);
				// parse error (missing end quote)
				if (i == tag_end)
				{
					token = xml_parse_error;
					start = "missing end quote on attribute";
					callback(token, start, int(strlen(start)), nullptr, 0);
					break;
				}
				const int val_len = i - val_start;
				token = xml_attribute;
				callback(token, start, name_len, val_start, val_len);
			}
		}
	}
Exemple #6
0
	void xml_parse(string_view input
		, std::function<void(int, string_view, string_view)> callback)
	{
		char const* p = input.data();
		char const* end = input.data() + input.size();
		for (;p != end; ++p)
		{
			char const* start = p;
			// look for tag start
			for (; p != end && *p != '<'; ++p);

			if (p != start)
			{
				callback(xml_string, {start, std::size_t(p - start)}, {});
			}

			if (p == end) break;

			// skip '<'
			++p;
			if (p != end && p + 8 < end && string_begins_no_case("![CDATA[", p))
			{
				// CDATA. match '![CDATA['
				p += 8;
				start = p;
				while (p != end && !string_begins_no_case("]]>", p - 2)) ++p;

				// parse error
				if (p == end)
				{
					callback(xml_parse_error, "unexpected end of file", {});
					break;
				}

				callback(xml_string, {start, std::size_t(p - start - 2)}, {});
				continue;
			}

			// parse the name of the tag.
			for (start = p; p != end && *p != '>' && !is_space(*p); ++p);

			char const* tag_name_end = p;

			// skip the attributes for now
			for (; p != end && *p != '>'; ++p);

			// parse error
			if (p == end)
			{
				callback(xml_parse_error, "unexpected end of file", {});
				break;
			}

			TORRENT_ASSERT(*p == '>');

			char const* tag_end = p;
			if (*start == '/')
			{
				++start;
				callback(xml_end_tag, {start, std::size_t(tag_name_end - start)}, {});
			}
			else if (*(p - 1) == '/')
			{
				callback(xml_empty_tag, {start, std::size_t(std::min(tag_name_end - start, p - start - 1))}, {});
				tag_end = p - 1;
			}
			else if (*start == '?' && *(p - 1) == '?')
			{
				++start;
				callback(xml_declaration_tag, {start, std::size_t(std::min(tag_name_end - start, p - start - 1))}, {});
				tag_end = p - 1;
			}
			else if (start + 5 < p && std::memcmp(start, "!--", 3) == 0 && std::memcmp(p - 2, "--", 2) == 0)
			{
				start += 3;
				callback(xml_comment, {start, std::size_t(tag_name_end - start - 2)}, {});
				continue;
			}
			else
			{
				callback(xml_start_tag, {start, std::size_t(tag_name_end - start)}, {});
			}

			// parse attributes
			for (char const* i = tag_name_end; i < tag_end; ++i)
			{
				char const* val_start = nullptr;

				// find start of attribute name
				while (i != tag_end && is_space(*i)) ++i;
				if (i == tag_end) break;
				start = i;
				// find end of attribute name
				while (i != tag_end && *i != '=' && !is_space(*i)) ++i;
				std::size_t const name_len = std::size_t(i - start);

				// look for equality sign
				for (; i != tag_end && *i != '='; ++i);

				// no equality sign found. Report this as xml_tag_content
				// instead of a series of key value pairs
				if (i == tag_end)
				{
					callback(xml_tag_content, {start, std::size_t(i - start)}, {});
					break;
				}

				++i;
				while (i != tag_end && is_space(*i)) ++i;
				// check for parse error (values must be quoted)
				if (i == tag_end || (*i != '\'' && *i != '\"'))
				{
					callback(xml_parse_error, "unquoted attribute value", {});
					break;
				}
				char quote = *i;
				++i;
				val_start = i;
				for (; i != tag_end && *i != quote; ++i);
				// parse error (missing end quote)
				if (i == tag_end)
				{
					callback(xml_parse_error, "missing end quote on attribute", {});
					break;
				}
				callback(xml_attribute, {start, name_len}, {val_start, std::size_t(i - val_start)});
			}
		}
	}