Chromium 'net' library reference usage for HTTP interaction purposes

292 views
Skip to first unread message

Sergey Kipet

unread,
Sep 28, 2017, 10:51:51 AM9/28/17
to Chromium-dev
Hi Guys,

Could someone please provide a reference to some (or several at once) up-to-date (valid) example (examples) of using the Chromium 'net' library for interaction with a host over HTTP by sending plain requests and handling corresponding responses (as well as best practices related to the scope, e.g. thread-safety, request spawning environment, events and callbacks handling, etc.)? (Reading https://www.chromium.org/developers/design-documents/network-stack as well as https://chromium.googlesource.com/chromium/src/+/lkgr/net/docs/life-of-a-url-request.md, unfortunately, was not sufficient to get started with %)) Would appreciate it very much for any direction (tip) provided.

Sorry for duplicating the topic (if any) in advance.

Thank you.

BRs,
Sergey Kipet.

Matthew Menke

unread,
Sep 28, 2017, 1:34:39 PM9/28/17
to Chromium-dev, net-dev
Unfortunately, we only have officially supported APIs on Android and iOS (See src/components/cronet).  We have Android examples, I assume we have iOS ones as well.

If you want to use the C++ API, it's probably easiest to start with URLRequestContextBuilder (which has a lot of configuration options, but can issue network requests with just using its default configuraiton) and URLFetcher or URLRequest.  The classes are all single threaded.  URLFetcher is simpler and can work across threads, though it's less powerful.  The code does assume you're using Chrome's threading libraries.  If you're not, setting up threads may be a bit tricky.

Sergey Kipet

unread,
Sep 28, 2017, 4:12:51 PM9/28/17
to Chromium-dev, net...@chromium.org
Hi Matthew,

Thank you so much for your reply, I do appreciate it.

You mean these APIs are not officially supported either on Unix-like platforms or any other non-mobile systems, don't you? Does it mean that they can be used on a platform other than Android or iOS though (with some possible constraints)? (I actually was going to engage the C++ APIs on Linux.)

Can the types you have mentioned above be used in a multithreading environment? (Had an idea to just spawn a dedicated thread for polling a host by using a timer as well as the APIs to interact with the host over HTTP).

Thanks.

BRs,
Sergey Kipet.

четверг, 28 сентября 2017 г., 20:34:39 UTC+3 пользователь Matthew Menke написал:

Sergey Kipet

unread,
Oct 4, 2017, 1:17:17 PM10/4/17
to Chromium-dev
Hi Guys,

Found some tiny app within the net/tools/get_server_time folder and tried its approach for sending a HTTP-request to a host. If the following code snippet (got from the found sample app):

    base::MessageLoopForIO main_loop;

  QuitDelegate delegate;
  std::unique_ptr<net::URLFetcher> fetcher =
      net::URLFetcher::Create(GURL(fetch_url.c_str()), net::URLFetcher::GET,
                              &delegate);
  std::unique_ptr<net::URLRequestContext> url_request_context(
      BuildURLRequestContext());
  fetcher->SetRequestContext(
      // Since there's only a single thread, there's no need to worry
      // about when the URLRequestContext gets created.
      // The URLFetcher will take a reference on the object, and hence
      // implicitly take ownership.
      new net::TrivialURLRequestContextGetter(url_request_context.get(),
                                              main_loop.task_runner()));

  fetcher->Start();

  // |delegate| quits |main_loop| when the request is done.
  base::RunLoop().Run();

  const net::URLRequestStatus status = fetcher->GetStatus();
  if (status.status() != net::URLRequestStatus::SUCCESS) {
    LOG(ERROR) << __func__ << "Request failed with error code: "
               << net::ErrorToString(status.error());
  }


is placed into the main() function of a single-threaded sample app (even if it's wrapped by a loop to emulate repeating requests to some HTTP-host), it works just fine (except a corresponding delegate overridden member is never called, although it still gets correct HTTP-responses just as expected). But if I place it into a dedicated function bound to the base::Timer instance (repeating timer case) being a member of a custom thread (inherited from the base::Thread type), the created request is able to run correctly just once (for the very first time only). Any further attempt of the timer to fire and run a specified closure (with the code listed above) causes the application to crash with a backtrace generated as follows:

Received signal 11 SEGV_MAPERR 000000000000
#0 0x000001452c37 base::debug::StackTrace::StackTrace()
#1 0x0000014527af base::debug::(anonymous namespace)::StackDumpSignalHandler()
#2 0x7ff316bfc390 <unknown>
#3 0x0000014a45de base::ThreadTaskRunnerHandle::Get()
#4 0x0000014a521d base::Timer::PostNewScheduledTask()
#5 0x0000014a5444 base::Timer::RunScheduledTask()
#6 0x0000014cc170 base::debug::TaskAnnotator::RunTask()
#7 0x00000146925d base::MessageLoop::RunTask()
#8 0x0000014695a8 base::MessageLoop::DeferOrRunPendingTask()
#9 0x000001469aab base::MessageLoop::DoDelayedWork()
#10 0x00000146a65d base::MessagePumpDefault::Run()
#11 0x0000014836fe base::RunLoop::Run()
#12 0x0000014a3492 base::Thread::ThreadMain()
#13 0x00000149ee63 base::(anonymous namespace)::ThreadFunc()
#14 0x7ff316bf26ba start_thread
#15 0x7ff311b123dd clone
  r8: 0000000000000000  r9: 0000000000000000 r10: 00007ff2f83029d0 r11: 0000000000000206
 r12: 000013aee8bcd9a0 r13: 0000000000000000 r14: 00000000000186a0 r15: 000013aee8b05a80
  di: 0000000000000020  si: 0000000000000001  bp: 00007ff2f8302a50  bx: 00007ff2f8302758
  dx: 0000000000000000  ax: 0000000000000000  cx: 0000000000000090  sp: 00007ff2f8302730
  ip: 00000000014a45de efl: 0000000000010246 cgf: 0000000000000033 erf: 0000000000000004
 trp: 000000000000000e msk: 0000000000000000 cr2: 0000000000000000
[end of stack trace]
Calling _exit(1). Core file will not be generated.


Seems like a task runner for the current thread which the timer is trying to get has just disappeared after the first timer firing attempt. Any ideas on why this happened (and how to handle that correctly)?

Any either directions or thoughts are highly appreciated. Thank you.

P.S.
Specifying the custom thread spawned to use a message loop of the base::MessageLoop::TYPE_IO type as well as providing it to the net::TrivialURLRequestContextGetter instance (instead of base::MessageLoopForIO) prevents the URL-request from being even responded to.

BRs,
Sergey Kipet.

четверг, 28 сентября 2017 г., 17:51:51 UTC+3 пользователь Sergey Kipet написал:

Sergey Kipet

unread,
Oct 26, 2017, 10:48:07 AM10/26/17
to Chromium-dev
Hi everyone,

Just for keeping informed those who might be interested in the discussed topic. Well, I've finally solved the issue observed.

First of all, creation of a new message loop on the thread stack implies (implicit) attaching it to a current thread (as well as a task runner related to the message loop attached to the thread), thus, when an instance of the base::Timer object tries to post a new task (run a previously bound callback) next time (before the very first creation of the message loop) no existing task runner is found (due to the message loop object goes out of scope, thus, it is just destructed), which in fact causes the crashing (at debug time).

An obvious workaround for this (most probably one of many) is to avoid using the base::Timer instance, post a task (e.g. by using plain PostTask() within corresponding c-tor) you've been planning to repeatedly call (e.g., for polling a host via HTTP by using the Chromium net library) and place another posting of the same task (recursively at the first sight, but not being a real recursion in fact, e.g. via PostDelayTask()) within the task body making it as the last body statement.

Now, everything seems to be working just fine. Cheers.


Thank you.

BRs,
Sergey Kipet.




среда, 4 октября 2017 г., 20:17:17 UTC+3 пользователь Sergey Kipet написал:
Reply all
Reply to author
Forward
0 new messages