<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: djmitche</title>
    <description>The latest articles on DEV Community by djmitche (@djmitche).</description>
    <link>https://dev.to/djmitche</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F683206%2Fced67d8f-d5ea-49ff-aaeb-7b7c3cb76580.png</url>
      <title>DEV Community: djmitche</title>
      <link>https://dev.to/djmitche</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/djmitche"/>
    <language>en</language>
    <item>
      <title>Clipboards, Terminals, and Linux</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Fri, 29 Dec 2023 00:00:45 +0000</pubDate>
      <link>https://dev.to/djmitche/clipboards-terminals-and-linux-3pk5</link>
      <guid>https://dev.to/djmitche/clipboards-terminals-and-linux-3pk5</guid>
      <description>&lt;p&gt;I've recently switched to &lt;a href="https://neovim.io/" rel="noopener noreferrer"&gt;Neovim&lt;/a&gt;, and with it begun using the terminal mouse support. But, this has the side-effect that I can't just click-and-drag to select text in the terminal anymore -- Neovim controls that as well.&lt;/p&gt;

&lt;p&gt;Which leads me to clipboards. Linux has two of them! Adding to the interest, I typically use Neovim remotely, via an SSH connection to a &lt;a href="https://github.com/tmux/tmux/wiki" rel="noopener noreferrer"&gt;Tmux&lt;/a&gt; session. And on my Linux system, I use &lt;a href="https://wiki.archlinux.org/title/rxvt-unicode" rel="noopener noreferrer"&gt;urxvt&lt;/a&gt; as my terminal program. All of these are very UNIX-y tools, and somehow they all need to play nicely together.&lt;/p&gt;

&lt;p&gt;With this sort of challenge, typically the best approach is to learn as much as possible about the different parts, do some experimentation to see how they work in practice, and then try to stitch together a working solution. Sometimes Reddit posts or other information you come across can be useful, but as often as not it's wrong or outdated, so using it without understanding it might just make things more confusing.&lt;/p&gt;

&lt;p&gt;In the interest of sharing, here's some of what I've learned.&lt;/p&gt;

&lt;h1&gt;
  
  
  Security
&lt;/h1&gt;

&lt;p&gt;A brief word about security: clipboards often have passwords in them, especially if you use an external password manager like LastPass. So it's worth thinking carefully about what un-trusted software might be able to read from your clipboard.&lt;/p&gt;

&lt;p&gt;Depending on what you do with the information in this post, you might enable &lt;em&gt;any binary you run&lt;/em&gt; to access your clipboard from &lt;em&gt;any host you SSH to&lt;/em&gt;. Maybe that's OK in your situation, but it is worth thinking about.&lt;/p&gt;

&lt;h1&gt;
  
  
  X Clipboards
&lt;/h1&gt;

&lt;p&gt;X Windows has lots of "selections", but the two we'll be concerned with are PRIMARY and CLIPBOARD. Most times you select some text, that's automatically moved to the PRIMARY selection. When you specifically request copying a value (i.e., control-C), the value is put into the CLIPBOARD selection. Note that this means selecting some text and pressing Control-C will usually put that text in &lt;em&gt;both&lt;/em&gt; selections!&lt;/p&gt;

&lt;p&gt;The common &lt;code&gt;xclip&lt;/code&gt; utility can be used to get or set clipboards. And, there's a tiny little utility script called &lt;a href="https://github.com/cdown/clipnotify" rel="noopener noreferrer"&gt;clipnotify&lt;/a&gt; that I found really useful for debugging this. I cloned and built it, then ran it in a loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./clipnotify &lt;span class="nt"&gt;-l&lt;/span&gt; | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;x&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;clear
  &lt;span class="k"&gt;for &lt;/span&gt;s &lt;span class="k"&gt;in &lt;/span&gt;primary clipboard&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$s&lt;/span&gt;
    xclip &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-selection&lt;/span&gt; &lt;span class="nv"&gt;$s&lt;/span&gt;
    &lt;span class="nb"&gt;echo
  &lt;/span&gt;&lt;span class="k"&gt;done
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I ran this in a dedicated terminal so I could easily see what was in the X selections at all times.&lt;/p&gt;

&lt;h2&gt;
  
  
  OSC-52
&lt;/h2&gt;

&lt;p&gt;OSC-52 is how information about clipboards is transmitted over a terminal. This is an &lt;a href="https://en.wikipedia.org/wiki/ANSI_escape_code#OSC_(Operating_System_Command)_sequences" rel="noopener noreferrer"&gt;ANSI terminal escape&lt;/a&gt;, so a bunch of bytes beginning with ESC that mean something to a terminal emulator. There are a bunch of OSC codes, but 52 is the one that handles clipboards. Documentation is a little hard to find, so I'll summarize how it works here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Clipboard
&lt;/h2&gt;

&lt;p&gt;Sending the sequence &lt;code&gt;&amp;lt;ESC&amp;gt;]52;&amp;lt;board&amp;gt;;&amp;lt;content&amp;gt;&amp;lt;BEL&amp;gt;&lt;/code&gt; to the terminal sets clipboard &lt;code&gt;&amp;lt;board&amp;gt;&lt;/code&gt; to &lt;code&gt;&amp;lt;content&amp;gt;&lt;/code&gt;. Here &lt;code&gt;&amp;lt;ESC&amp;gt;&lt;/code&gt; is 0x1b and &lt;code&gt;&amp;lt;BEL&amp;gt;&lt;/code&gt; is &lt;code&gt;0x07&lt;/code&gt;, sometimes written &lt;code&gt;\e&lt;/code&gt; and &lt;code&gt;\a&lt;/code&gt;, respectively. The &lt;code&gt;&amp;lt;content&amp;gt;&lt;/code&gt; is base64-encoded. The &lt;code&gt;&amp;lt;board&amp;gt;&lt;/code&gt; can be &lt;code&gt;c&lt;/code&gt; (clipboard) or &lt;code&gt;p&lt;/code&gt; (primary) on Linux, but things like MacOS only support &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can experiment with this with &lt;code&gt;printf&lt;/code&gt; in the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s1"&gt;]52;c;%s&lt;/span&gt;&lt;span class="se"&gt;\a&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;foobar | &lt;span class="nb"&gt;base64&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will put "foobar" in your clipboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Clipboard
&lt;/h2&gt;

&lt;p&gt;Sending the sequence &lt;code&gt;&amp;lt;ESC&amp;gt;52;&amp;lt;board&amp;gt;;?&amp;lt;BEL&amp;gt;&lt;/code&gt; to the terminal will "query" the value of &lt;code&gt;&amp;lt;board&amp;gt;&lt;/code&gt;. The terminal responds with a sequence like the "set clipboard' above, containing the content of the requested board.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;⸩ &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s1"&gt;]52;p;?&lt;/span&gt;&lt;span class="se"&gt;\a&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
^[]52&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="nv"&gt;Zm9vYmFyCg&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;^G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes a bit of a mess of the terminal, but you can see the response, and that base64 decodes to the value in the PRIMARY selection. &lt;/p&gt;

&lt;h2&gt;
  
  
  Advertising Support for OSC-52
&lt;/h2&gt;

&lt;p&gt;Terminals advertise their support for functionality via some really arcane symbols. The particular piece that indicates clipboards are supported is &lt;code&gt;Ms=\E]52%p1%s;%p2%s\007&lt;/code&gt;. This is typically found in the "terminfo" database, keyed by the terminal name, which an application finds in &lt;code&gt;$TERM&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;⸩ &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$TERM&lt;/span&gt;
rxvt-unicode-256color
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Bracketed Paste Mode
&lt;/h1&gt;

&lt;p&gt;While in principle "paste" into a terminal application can just pretend the pasted data was typed on a keyboard, in practice this can go very badly. For example, if pasting into Vim when it's not in insert mode, the result is usually a mess. Even in insert mode, if autoindent is enabled when you are pasting code, the indentation is not what's expected. Vim has a &lt;code&gt;paste&lt;/code&gt; option for this, but in fact there's a better way: &lt;a href="http://www.xfree86.org/current/ctlseqs.html#Bracketed%20Paste%20Mode" rel="noopener noreferrer"&gt;bracketed paste mode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An application using the terminal "sets" this mode, after which the terminal will prefix pasted content with &lt;code&gt;&amp;lt;ESC&amp;gt;[200~&lt;/code&gt; and suffix it with &lt;code&gt;&amp;lt;ESC&amp;gt;]200~&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can see this with a quick little Python program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\x1b&lt;/span&gt;&lt;span class="s"&gt;[?2004h&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# set bracketed-paste mode
&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\x1b&lt;/span&gt;&lt;span class="s"&gt;[?2004l&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# reset the mode
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  urxvt
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;urxvt&lt;/code&gt; terminal emulator doesn't support OSC-52 out of the box. Honestly, it does very little out of the box! But there's a tiny script, &lt;a href="https://github.com/parantapa/dotfiles/blob/100cabd431e80b3788d03c3c798e79fcbd06d6f3/urxvt-perl/52-osc" rel="noopener noreferrer"&gt;52-osc&lt;/a&gt; that adds this support. This is actually nice, because you can see what it does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;on_osc_seq&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$term&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="nv"&gt;$op&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$clip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;split&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?&lt;/span&gt;&lt;span class="p"&gt;')&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$data_free&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$term&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;selection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nn"&gt;Encode::&lt;/span&gt;&lt;span class="nv"&gt;_utf8_off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data_free&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;# XXX&lt;/span&gt;
        &lt;span class="nv"&gt;$term&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;tt_write&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;]52;&lt;/span&gt;&lt;span class="si"&gt;$clip&lt;/span&gt;&lt;span class="s2"&gt;;&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;encode_base64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data_free&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;'')&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\a&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$data_decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;decode_base64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nn"&gt;Encode::&lt;/span&gt;&lt;span class="nv"&gt;_utf8_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data_decoded&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;# XXX&lt;/span&gt;
        &lt;span class="nv"&gt;$term&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;selection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$data_decoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$clip&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/c/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$term&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;selection_grab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;urxvt::&lt;/span&gt;&lt;span class="nv"&gt;CurrentTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$clip&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/c/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breaking that down, it's hooking into the OSC sequences, and specifically number 52. If it gets a query (&lt;code&gt;'?'&lt;/code&gt;), it gets the current selection from &lt;code&gt;$term-&amp;gt;selection()&lt;/code&gt; and sends that back to the app running in the terminal in an OSC-52 escape, using &lt;code&gt;$term-&amp;gt;tt_write()&lt;/code&gt;. Otherwise, it decodes the data and sets the X selection with &lt;code&gt;$term-&amp;gt;selection(data, clipboard)&lt;/code&gt;. The &lt;code&gt;/c/&lt;/code&gt; is a regular expression matching &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Putting the &lt;code&gt;printf&lt;/code&gt; and &lt;code&gt;clipnotify&lt;/code&gt; bits from above together shows that when &lt;code&gt;&amp;lt;board&amp;gt;&lt;/code&gt; is &lt;code&gt;c&lt;/code&gt; then this plugin updates the CLIPBOARD selection, otherwise PRIMARY. This still works over an SSH connection to a remote host.&lt;/p&gt;

&lt;p&gt;Unfortunately, because this is accomplished with a plugin, the terminal info for urxvt doesn't advertise this support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copy and Paste
&lt;/h2&gt;

&lt;p&gt;Urxvt has a built-in plugin, &lt;code&gt;selection-to-clipboard&lt;/code&gt;, to copy every selection to the clipboard. In fact, it populates both the PRIMARY and CLIPBOARD selections.&lt;/p&gt;

&lt;p&gt;Right-click will paste from the PRIMARY selection. With the following in &lt;code&gt;.Xresources&lt;/code&gt;, shift-ctrl-V will paste from the CLIPBOARD selection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rxvt.keysym.Shift-Control-V: eval:paste_clipboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Either paste option supports bracketed-paste mode.&lt;/p&gt;

&lt;h1&gt;
  
  
  tmux
&lt;/h1&gt;

&lt;p&gt;I typically run &lt;code&gt;tmux&lt;/code&gt; on remote systems, so that I can leave everything running while my laptop is asleep, or if I lose my network connection. Tmux is basically a terminal emulator that runs in a terminal: you can run other things in a tmux window, and tmux lets you switch between those windows, show them on different systems, etc. But, that means that tmux is intercepting terminal escape codes, whether they're for cursor positioning or clipboard management. It is then using (possibly different) escape codes to draw the tmux UI on your terminal.&lt;/p&gt;

&lt;p&gt;In its default settings, the &lt;code&gt;printf&lt;/code&gt; above won't do anything in tmux when running inside urxvt, because urxvt doesn't advertise support for it. That can be fixed in &lt;code&gt;.tmux.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set-option -ga terminal-override ',rxvt-uni*:XT:Ms=\E]52;%p1%s;%p2%s\007'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this "fix" only works for things running in tmux. I do everything in tmux (even locally), so it's fine for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Buffers
&lt;/h2&gt;

&lt;p&gt;Tmux has a concept of &lt;a href="https://man7.org/linux/man-pages/man1/tmux.1.html#BUFFERS" rel="noopener noreferrer"&gt;buffers&lt;/a&gt; which are named bits of text that can be injected into an application as if they were keyboard input. Tmux also has a "copy mode" where keyboard navigation can be used to select text that will be put into a buffer. The concept is pretty general, although I don't know what would be built from it.&lt;/p&gt;

&lt;p&gt;Tmux is designed around the idea that you would only use buffers for copy/paste. That isn't especially practical, since for example web browsers tend not to be terminal applications!&lt;/p&gt;

&lt;h2&gt;
  
  
  Clipboard Integration
&lt;/h2&gt;

&lt;p&gt;Tmux has &lt;a href="https://github.com/tmux/tmux/wiki/Clipboard" rel="noopener noreferrer"&gt;a wiki page about clipboards&lt;/a&gt;. The main integration is &lt;code&gt;set-clipboard&lt;/code&gt;. If this is "external", then tmux will issue an OSC-52 sequence to update the system clipboard whenever a buffer is set. If this is &lt;code&gt;on&lt;/code&gt;, then tmux will additionally accept OSC-52 sequences from applications running inside it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set-option -g set-clipboard on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With both of these options set, repeating the same experiment within a tmux session reveals that any OSC-52 sequence now updates only the PRIMARY selection. That is, the implementation of &lt;code&gt;set-clipboard&lt;/code&gt; only updates the PRIMARY selection.&lt;/p&gt;

&lt;p&gt;Furthermore, running the get-clipboard &lt;code&gt;printf&lt;/code&gt; from above confirms that tmux only returns its own paste buffer -- it never queries the external terminal emulator for the value of the system clipboard.&lt;/p&gt;

&lt;p&gt;Even tmux's support for external commands &lt;em&gt;only&lt;/em&gt; supports copy operations. There's no way to feed data on the system clipboard into tmux.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bracketed Paste
&lt;/h2&gt;

&lt;p&gt;When an application in a tmux pane has bracketed paste enabled, tmux will enable it in the parent terminal. It will also "pass through" the brackets from that parent terminal when a paste is performed. Basically, it just works.&lt;/p&gt;

&lt;p&gt;Tmux also has a &lt;code&gt;-p&lt;/code&gt; option to its &lt;code&gt;paste-buffer&lt;/code&gt; command to bracket the buffer contents.&lt;/p&gt;

&lt;h1&gt;
  
  
  Neovim
&lt;/h1&gt;

&lt;p&gt;Neovim's &lt;code&gt;:help clipboard&lt;/code&gt; lays out the situation pretty clearly, and it works quite nicely out of the box. It uses &lt;code&gt;xsel&lt;/code&gt; to interact directly with X selections when &lt;code&gt;$DISPLAY&lt;/code&gt; is set, and it uses &lt;code&gt;tmux&lt;/code&gt; commands when running in tmux. Its &lt;code&gt;checkhealth&lt;/code&gt; command makes it easy to see what it's chosen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;vim&lt;/code&gt; run locally, outside of tmux: xsel&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vim&lt;/code&gt; run locally, in tmux: xsel&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vim&lt;/code&gt; run via SSH, outside of tmux: no support&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vim&lt;/code&gt; run via SSH, in tmux: tmux&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here, I'm not forwarding X11 via SSH. If I do so, and install &lt;code&gt;xsel&lt;/code&gt; remotely, then Neovim will use xsel in all four of the above situations.&lt;/p&gt;

&lt;p&gt;Tmux does enable bracketed paste mode.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;All in all, this is not pretty!&lt;/p&gt;

&lt;p&gt;Two clipboards (selections), handled slightly differently by each application -- so maybe copy in one app doesn't use the same selection that paste does in another. That's certainly more than ctrl-c/ctrl-v muscle memory can deal with, especially for those who also use more .. ahem .. user-friendly systems on a daily basis.&lt;/p&gt;

&lt;p&gt;Most people think of having one clipboard.&lt;/p&gt;

&lt;p&gt;Tmux is a pretty substantial impediment here, too, basically rendering tmux's buffers useless, since they can't mirror the "one clipboard".&lt;/p&gt;

&lt;p&gt;At any rate, this continues my habit of writing posts as a way to learn about a new topic. I hope this information is useful to others as well!&lt;/p&gt;

</description>
      <category>linux</category>
      <category>cli</category>
      <category>terminal</category>
      <category>clipboard</category>
    </item>
    <item>
      <title>Collaborating with CLs in Chromium</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Mon, 23 Oct 2023 19:11:22 +0000</pubDate>
      <link>https://dev.to/djmitche/collaborating-with-cls-in-chromium-2gab</link>
      <guid>https://dev.to/djmitche/collaborating-with-cls-in-chromium-2gab</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;EDITED&lt;/strong&gt; to address issues with downstream CLs when the colleague's CL is updated.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'm working closely with some of my colleagues on a project, meaning that we are frequently working on functionality that depends on CLs still in review, written by other people. The Chromium docs on how to handle this are out-of-date and contradictory, so in the fine blogging tradition of making a post so I don't forget something, here it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I make a CL that depends on another CL?
&lt;/h2&gt;

&lt;p&gt;When you &lt;code&gt;git cl upload&lt;/code&gt;, depot-tools looks in the Git history for your HEAD commit, until it finds another branch. If that branch has dependency information (unclear if that's in &lt;code&gt;.git/config&lt;/code&gt; or a &lt;code&gt;Change-Id: ..&lt;/code&gt; header in its commit message), then the upload will link the CLs. &lt;/p&gt;

&lt;p&gt;First, get a local copy of the parent CL, and give it an appropriate branch name. This is my pattern, but it is only local do what suits you best!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cl patch &lt;span class="nt"&gt;-b&lt;/span&gt; bug-&lt;span class="nv"&gt;$NUM&lt;/span&gt;-&lt;span class="nv"&gt;$USERNAME&lt;/span&gt;-&lt;span class="nv"&gt;$SUMMARY&lt;/span&gt; &lt;span class="nv"&gt;$GERRIT_URL&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may give an error about hashes not matching, but that's OK, since you won't be uploading to that CL. I suspect this has something to do with the committer name / email.&lt;/p&gt;

&lt;p&gt;Then, make a new branch with that one as the upstream.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git new-branch &lt;span class="nt"&gt;--upstream-current&lt;/span&gt; bug-&lt;span class="nv"&gt;$NUM&lt;/span&gt;-&lt;span class="nv"&gt;$MY_SUMMARY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make your changes. When you're ready to upload, do so as usual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cl upload &lt;span class="nt"&gt;--cp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;--cp&lt;/code&gt; is telling the command to not try to upload all of the other CLs in the stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating the Parent CL
&lt;/h2&gt;

&lt;p&gt;When the CL you're depending on is updated, you need to use precisely the right formulation of &lt;code&gt;git cl patch&lt;/code&gt; or things will go wildly off the rails.&lt;/p&gt;

&lt;p&gt;Switch to the branch containing that parent CL and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cl patch &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="nt"&gt;--reapply&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;do &lt;em&gt;not&lt;/em&gt; use &lt;code&gt;--pull&lt;/code&gt; - I think that does something like pulling &lt;code&gt;origin/main&lt;/code&gt; and rebasing on top of it? At any rate, it's a bad idea.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Chromium Spelunking: Connecting to Proxies</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Thu, 28 Sep 2023 20:39:57 +0000</pubDate>
      <link>https://dev.to/djmitche/chromium-spelunking-connecting-to-proxies-fo</link>
      <guid>https://dev.to/djmitche/chromium-spelunking-connecting-to-proxies-fo</guid>
      <description>&lt;p&gt;Having &lt;a href="https://dev.to/djmitche/chromium-spelunking-the-io-thread-464n"&gt;successfully fetched a URL&lt;/a&gt; with the Chromium network stack, it's time to return to the reason I began this journey: how does Chromium connect to proxies?&lt;/p&gt;

&lt;h2&gt;
  
  
  Proxy Review
&lt;/h2&gt;

&lt;p&gt;First, a quick review of HTTP proxying.&lt;/p&gt;

&lt;p&gt;In the beginning, there was a simple protocol to proxy an HTTP transaction: connect to a proxy and, instead of sending just a path in the request line, send the entire URL. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET http://httbin.org/uuid HTTP/1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proxy server then makes an outbound connection to &lt;code&gt;httpbin.org&lt;/code&gt;, sends &lt;code&gt;GET /uuid HTTP/1.1&lt;/code&gt; with the headers supplied by the client, and then relays the response back to the client.&lt;/p&gt;

&lt;p&gt;This sort of proxy exposes all of the details of the transaction to the proxy (or to anyone, if not using TLS for the connection to the proxy). If the origin URL has scheme &lt;code&gt;https&lt;/code&gt;, the &lt;em&gt;proxy&lt;/em&gt; will use TLS to connect to the origin, but will still handle the transaction content in cleartext. This has some obvious downsides, but an advantage is that the proxy can cache responses, saving bandwidth. This was a popular use of proxies in the aughts, but is far less common now that bandwidth is cheap and privacy is important.&lt;/p&gt;

&lt;p&gt;An alternative method, &lt;code&gt;CONNECT&lt;/code&gt;, was defined &lt;a href="https://datatracker.ietf.org/doc/html/rfc2817" rel="noopener noreferrer"&gt;about 25 years ago&lt;/a&gt;. It creates a "tunnel" through the proxy which can carry arbitrary data to and from another host. The request looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CONNECT httpbin.org:443 HTTP/1.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proxy server makes a TCP connection to the given host and port, sends back a response header, and then forwards bytes bidirectionally without further analyzing them. In fact, that protocol doesn't have to be HTTP (but it must use TCP, which will become important later).&lt;/p&gt;

&lt;p&gt;To test proxying,I'm using &lt;a href="https://tinyproxy.github.io/" rel="noopener noreferrer"&gt;tinyproxy&lt;/a&gt;, running a very simple config on port 8080. This supports SPDY (HTTP/2), which is a complication I don't really want to consider at this point, but the analysis ends up quite similar to HTTP/1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring a Proxy
&lt;/h2&gt;

&lt;p&gt;So, how does the network service decide to use a proxy for a request? It's complicated.&lt;/p&gt;

&lt;p&gt;Let's start at the bottom. &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/base/proxy_server.h" rel="noopener noreferrer"&gt;&lt;code&gt;net::ProxyServer&lt;/code&gt;&lt;/a&gt; defines an actual server to connect to. It has a scheme, host, and port. One of those schemes is "DIRECT" which means do not use a proxy. The others include HTTP, HTTPS, SOCKS, and QUIC, and just describe how to connect to the proxy server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/proxy_resolution/proxy_list.h" rel="noopener noreferrer"&gt;&lt;code&gt;net::ProxyList&lt;/code&gt;&lt;/a&gt; represents a list of &lt;code&gt;ProxyServer&lt;/code&gt; instances and handles fallback from one to the next. This allows, for example, an enterprise to configure traffic to go via a local proxy but fall back to DIRECT when that proxy is down, such as when using a caching proxy.&lt;/p&gt;

&lt;p&gt;Scoping out another level, &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/proxy_resolution/proxy_config.h" rel="noopener noreferrer"&gt;&lt;code&gt;net::ProxyConfig&lt;/code&gt;&lt;/a&gt; represents a configuration for when to use which proxies. This can be manually configured or can refer to a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_PAC_file" rel="noopener noreferrer"&gt;PAC script&lt;/a&gt; that defines the configuration.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ProxyConfig&lt;/code&gt; comes from a &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/proxy_resolution/proxy_config_service.h?q=net::ProxyConfigService" rel="noopener noreferrer"&gt;&lt;code&gt;net::ProxyConfigService&lt;/code&gt;&lt;/a&gt;, which is used by a &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/proxy_resolution/configured_proxy_resolution_service.h" rel="noopener noreferrer"&gt;&lt;code&gt;net::ProxyResolutionService&lt;/code&gt;&lt;/a&gt; to determine the &lt;code&gt;ProxyList&lt;/code&gt; to use for a given URL. There's a lot of complexity here that we won't get into, including auto-configuration of proxies and downloading and executing PAC scripts, but the end result is a &lt;code&gt;ProxyList&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;churl&lt;/code&gt;, we want to hard-code a proxy, so I updated the &lt;code&gt;ProxyConfigService&lt;/code&gt; I defined &lt;a href="https://dev.to/djmitche/chromium-spelunking-churl-5dof"&gt;earlier in this series&lt;/a&gt; to return a config pointing to a proxy server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProxyConfigServiceHardCoded&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ProxyConfigService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nl"&gt;public:&lt;/span&gt;
  &lt;span class="c1"&gt;// ProxyConfigService implementation:&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;AddObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Observer&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;RemoveObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Observer&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ProxyConfigService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ConfigAvailability&lt;/span&gt; &lt;span class="n"&gt;GetLatestProxyConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ProxyConfigWithAnnotation&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;traffic_annotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kHardCodedProxyTrafficAnnotation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;proxy_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ProxyConfig&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CreateDirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;proxy_rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proxy_config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;proxy_rules&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;proxy_rules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFromString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"localhost:8080"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ProxyConfigWithAnnotation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proxy_config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;traffic_annotation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CONFIG_VALID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tracing a Simple Request
&lt;/h2&gt;

&lt;p&gt;OK, let's see how this works. My strategy for this sort of investigation is to add lots of debugging output -- at the beginning of each relevant function, and sometimes at key points in longer functions. Then I can follow execution within the source, comparing to the debugging output. I prefer this approach over using a debugger like GDB because I find it more efficient. Use the tools you prefer!&lt;/p&gt;

&lt;p&gt;I'll be making a request to &lt;code&gt;https://ip.cow.org&lt;/code&gt; using tinyproxy running on &lt;code&gt;http://localhost:8080&lt;/code&gt;. Because the origin URL is &lt;code&gt;https&lt;/code&gt;, this should use &lt;code&gt;CONNECT&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP Cache
&lt;/h3&gt;

&lt;p&gt;We saw in previous posts that the URLRequest ends up using an &lt;code&gt;HttpTransactionFactory::CreateTransaction&lt;/code&gt; to create an &lt;code&gt;HttpCache::Transaction&lt;/code&gt;, and starting it. That class has a rather large number of states, but adding some logging in &lt;code&gt;DoLoop&lt;/code&gt; shows the sequence of states (formatted to fit your screen):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HttpCache::Transaction -&amp;gt; STATE_GET_BACKEND
HttpCache::Transaction -&amp;gt; STATE_GET_BACKEND_COMPLETE
HttpCache::Transaction -&amp;gt; STATE_INIT_ENTRY
HttpCache::Transaction -&amp;gt; STATE_OPEN_OR_CREATE_ENTRY
HttpCache::Transaction -&amp;gt; STATE_OPEN_OR_CREATE_ENTRY_COMPLETE
HttpCache::Transaction -&amp;gt; STATE_ADD_TO_ENTRY
HttpCache::Transaction -&amp;gt; STATE_ADD_TO_ENTRY_COMPLETE
HttpCache::Transaction -&amp;gt; STATE_SEND_REQUEST
[0925/201309.849178:ERROR:churl_bin.cc(89)] OnConnected
HttpCache::Transaction -&amp;gt; STATE_SEND_REQUEST_COMPLETE
HttpCache::Transaction -&amp;gt; STATE_FINISH_HEADERS
HttpCache::Transaction -&amp;gt; STATE_SUCCESSFUL_SEND_REQUEST
HttpCache::Transaction -&amp;gt; STATE_OVERWRITE_CACHED_RESPONSE
HttpCache::Transaction -&amp;gt; STATE_CACHE_WRITE_RESPONSE
HttpCache::Transaction -&amp;gt; STATE_CACHE_WRITE_RESPONSE_COMPLETE
HttpCache::Transaction -&amp;gt; STATE_TRUNCATE_CACHED_DATA
HttpCache::Transaction -&amp;gt; STATE_TRUNCATE_CACHED_DATA_COMPLETE
HttpCache::Transaction -&amp;gt; STATE_PARTIAL_HEADERS_RECEIVED
HttpCache::Transaction -&amp;gt; STATE_FINISH_HEADERS
HttpCache::Transaction -&amp;gt; STATE_FINISH_HEADERS_COMPLETE
[0925/201310.106633:ERROR:churl_bin.cc(165)] OnResponseStarted
[0925/201310.106669:ERROR:churl_bin.cc(171)] Got HTTP response code 200
HttpCache::Transaction -&amp;gt; STATE_NETWORK_READ_CACHE_WRITE
HttpCache::Transaction -&amp;gt; STATE_NETWORK_READ_CACHE_WRITE_COMPLETE
HttpCache::Transaction -&amp;gt; STATE_NETWORK_READ_CACHE_WRITE
HttpCache::Transaction -&amp;gt; STATE_NETWORK_READ_CACHE_WRITE_COMPLETE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So this provides a map to focus on what's going on in this particular request. Looking at the code, the backend- and entry-related items are just looking for values in the cache, of which there are none. The &lt;code&gt;OnConnected&lt;/code&gt; callback in the URLRequest delegate occurs during the &lt;code&gt;STATE_SEND_REQUEST&lt;/code&gt; segment. So let's dig in there.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HttpCache::Transaction::DoStartRequest&lt;/code&gt; calls &lt;code&gt;cache_-&amp;gt;network_layer_-&amp;gt;CreateTransaction(..)&lt;/code&gt;. That &lt;code&gt;network_layer_&lt;/code&gt; is another &lt;code&gt;HttpTransactionFactory&lt;/code&gt;. The &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_transaction_factory.h;l=20;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;bpv=1;bpt=1" rel="noopener noreferrer"&gt;code-search&lt;/a&gt; for that class shows a few classes that extend it, and a little debug printing reveals that this layer is an &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_network_layer.h;l=21;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;bpv=1;bpt=1" rel="noopener noreferrer"&gt;&lt;code&gt;HttpNetworkLayer&lt;/code&gt;&lt;/a&gt;, and &lt;code&gt;CreateTransaction&lt;/code&gt; returns an &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_network_transaction.h;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;bpv=1;bpt=1;l=50" rel="noopener noreferrer"&gt;&lt;code&gt;HttpNetworkTransaction&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP Network Layer
&lt;/h3&gt;

&lt;p&gt;This class also has a large collection of states, but the same trick helps us find the right one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HttpNetworkTransaction -&amp;gt; STATE_NOTIFY_BEFORE_CREATE_STREAM
HttpNetworkTransaction -&amp;gt; STATE_CREATE_STREAM        
HttpNetworkTransaction -&amp;gt; STATE_CREATE_STREAM_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_CONNECTED_CALLBACK     
[0925/205926.726872:ERROR:churl_bin.cc(89)] OnConnected
HttpNetworkTransaction -&amp;gt; STATE_CONNECTED_CALLBACK_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_INIT_STREAM
HttpNetworkTransaction -&amp;gt; STATE_INIT_STREAM_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_GENERATE_PROXY_AUTH_TOKEN
HttpNetworkTransaction -&amp;gt; STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_GENERATE_SERVER_AUTH_TOKEN
HttpNetworkTransaction -&amp;gt; STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_INIT_REQUEST_BODY
HttpNetworkTransaction -&amp;gt; STATE_INIT_REQUEST_BODY_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_BUILD_REQUEST 
HttpNetworkTransaction -&amp;gt; STATE_BUILD_REQUEST_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_SEND_REQUEST
HttpNetworkTransaction -&amp;gt; STATE_SEND_REQUEST_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_READ_HEADERS
HttpNetworkTransaction -&amp;gt; STATE_READ_HEADERS_COMPLETE
[0925/225438.616076:ERROR:churl_bin.cc(165)] OnResponseStarted
[0925/225438.616113:ERROR:churl_bin.cc(171)] Got HTTP response code 200
HttpNetworkTransaction -&amp;gt; STATE_READ_BODY
HttpNetworkTransaction -&amp;gt; STATE_READ_BODY_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_READ_BODY
HttpNetworkTransaction -&amp;gt; STATE_READ_BODY_COMPLETE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;STATE_CONNECTED_CALLBACK&lt;/code&gt; is just calling the &lt;code&gt;OnConnected&lt;/code&gt; callback. The more interesting bit is in the states before that, &lt;code&gt;STATE_CREATE_STREAM(_COMPLETE)&lt;/code&gt;. The important bit of this state seems to be calling &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_stream_factory.h;l=80" rel="noopener noreferrer"&gt;&lt;code&gt;HttpStreamFactory::RequestStream&lt;/code&gt;&lt;/a&gt;. This calls back through a delegate method named &lt;code&gt;OnStreamReady&lt;/code&gt;, and in this case &lt;code&gt;HttpStreamFactory&lt;/code&gt; itself is the delegate. Adding a debug print in its &lt;code&gt;OnStreamReady&lt;/code&gt; method shows that &lt;code&gt;used_proxy_info&lt;/code&gt; includes &lt;code&gt;localhost:8080&lt;/code&gt;, so that stream involves the proxy.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP Stream
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;HttpStreamFactory&lt;/code&gt; class has three nested helper classes: &lt;code&gt;JobFactory&lt;/code&gt;, &lt;code&gt;Job&lt;/code&gt;, and &lt;code&gt;JobController&lt;/code&gt;. The &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_stream_factory_job.h;l=493?q=HttpStreamFactory::JobFactory&amp;amp;ss=chromium%2Fchromium%2Fsrc" rel="noopener noreferrer"&gt;&lt;code&gt;HttpStreamFactory::JobFactory&lt;/code&gt;&lt;/a&gt; class is trivial: it has a &lt;code&gt;CreateJob&lt;/code&gt; method that calls the &lt;code&gt;Job&lt;/code&gt; constructor. I suspect this was done as a kind of &lt;a href="https://en.wikipedia.org/wiki/Dependency_injection" rel="noopener noreferrer"&gt;dependency injection&lt;/a&gt; to support testing the &lt;code&gt;JobController&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_stream_factory_job_controller.h;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;l=33" rel="noopener noreferrer"&gt;&lt;code&gt;HttpStreamFactory::JobController&lt;/code&gt;&lt;/a&gt; is a bit more interesting: it has a small state machine that simply resolves the proxy and then creates some jobs. The proxy resolution simply calls the &lt;code&gt;ProxyResolutionService&lt;/code&gt; described above. Some debug prints confirm that this returns a &lt;code&gt;ProxyInfo&lt;/code&gt; containing &lt;code&gt;localhost:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The job controller manages several jobs that run in parallel, implementing the "happy eyeballs" that I mentioned in the &lt;a href="https://dev.to/djmitche/chromium-spelunking-life-and-times-536b"&gt;Life and Times&lt;/a&gt; post. All of these jobs are implemented with the same class. I would have expected different job subclasses per job type. Anyway, since we're not using QUIC or pre-connecting or any of that stuff, we'll just focus on the "MAIN" job.&lt;/p&gt;

&lt;p&gt;Among many parameters, the &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_stream_factory_job.h;l=54?q=HttpStreamFactory::JobFactory&amp;amp;ss=chromium%2Fchromium%2Fsrc" rel="noopener noreferrer"&gt;&lt;code&gt;HttpStreamFactory::Job&lt;/code&gt;&lt;/a&gt; constructor takes a &lt;code&gt;ProxyInfo&lt;/code&gt;, so we can look for where that is used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HttpStreamFactory::Job -&amp;gt; STATE_START                                                                                                  
HttpStreamFactory::Job -&amp;gt; STATE_WAIT
HttpStreamFactory::Job -&amp;gt; STATE_WAIT_COMPLETE
HttpStreamFactory::Job -&amp;gt; STATE_INIT_CONNECTION
HttpStreamFactory::Job -&amp;gt; STATE_INIT_CONNECTION_COMPLETE
HttpStreamFactory::Job -&amp;gt; STATE_CREATE_STREAM
HttpStreamFactory::Job -&amp;gt; STATE_CREATE_STREAM_COMPLETE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;STATE_WAIT(_COMPLETE)&lt;/code&gt; states are related to the job controller's coordination of multiple parallel jobs. The interesting bit is &lt;code&gt;STATE_INIT_CONNECTION&lt;/code&gt;, in the &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_stream_factory_job.cc;l=740;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;bpv=1;bpt=1" rel="noopener noreferrer"&gt;&lt;code&gt;HttpStreamFactory::Job::DoInitConnectionImpl&lt;/code&gt;&lt;/a&gt; method. This method embodies dozens of concerns -- in my opinion this a perfect example of how not to implement something like this. But, ignoring QUIC, SPDY, WebSockets, TLS, PRECONNECT, and all the rest, it comes down to a call to &lt;code&gt;InitSocketHandleForHttpRequest&lt;/code&gt;, passing along the &lt;code&gt;ProxyInfo&lt;/code&gt; and a plethora of additional arguments.&lt;/p&gt;

&lt;p&gt;Let's take a moment here to notice the shift from deeply nested Java-style factories and controllers to a plain old C-style function. There's probably some interesting history here, perhaps in who wrote which bits of this code, or when they were written.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP Connection Pools
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/socket/client_socket_pool_manager.cc?q=InitSocketHandleForHttpRequest" rel="noopener noreferrer"&gt;&lt;code&gt;InitSocketHandleForHttpRequest&lt;/code&gt;&lt;/a&gt;, or more accurately &lt;code&gt;InitSocketPoolHelper&lt;/code&gt;, gets a pool from the current &lt;code&gt;HttpNetworkSession&lt;/code&gt; with &lt;code&gt;session-&amp;gt;GetSocketPool(socket_pool_type, proxy_info.proxy_server())&lt;/code&gt;. In this case the &lt;code&gt;socket_pool_type&lt;/code&gt; is &lt;code&gt;NORMAL_SOCKET_POOL&lt;/code&gt;, so this amounts to a call to &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/socket/client_socket_pool_manager_impl.cc;l=59;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;bpv=1;bpt=1" rel="noopener noreferrer"&gt;&lt;code&gt;ClientSocketPoolManagerImpl::GetSocketPool&lt;/code&gt;&lt;/a&gt; passing the proxy server through which the connection should be made (which might be &lt;code&gt;ProxyServer::Direct()&lt;/code&gt; when not using a proxy). The function also creates a &lt;code&gt;ClientSocketPool::GroupId&lt;/code&gt; built from the endpoint URL (&lt;code&gt;ip.cow.org&lt;/code&gt; in this case) and a few partitioning parameters.&lt;/p&gt;

&lt;p&gt;Summarizing, then, the &lt;code&gt;HttpNetworkSession&lt;/code&gt; stores a connection pool for each proxy server (including direct), and within each pool indexes connections by group ID.&lt;/p&gt;

&lt;p&gt;When a socket in a socket pool is claimed, that claim is represented by a &lt;code&gt;ClientSocketHandle&lt;/code&gt;, an empty instance of which is among the parameters to &lt;code&gt;InitSocketHandleForHttpRequest&lt;/code&gt;, which calls &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/socket/client_socket_handle.cc?q=ClientSocketHandle::Init" rel="noopener noreferrer"&gt;&lt;code&gt;ClientSocketHandle::Init(..)&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This &lt;code&gt;Init&lt;/code&gt; method calls the pool's &lt;code&gt;RequestSocket&lt;/code&gt; method. There are two implementations of this method, one of which is for WebSockets, so in this case we're calling &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/socket/transport_client_socket_pool.cc;l=244;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;bpv=1;bpt=1" rel="noopener noreferrer"&gt;&lt;code&gt;TransportClientSocketPool::RequestSocket&lt;/code&gt;&lt;/a&gt; and on to &lt;code&gt;TransportClientSocketPool::RequestSocketInternal&lt;/code&gt;. Assuming that there are no existing connections in the pool, and there are free slots to create new connections, this makes a new connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Connection
&lt;/h3&gt;

&lt;p&gt;This occurs with another set of jobs and job factories, this time with subclasses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/socket/client_socket_pool.cc;l=171?q=ClientSocketPool::CreateConnectJob" rel="noopener noreferrer"&gt;&lt;code&gt;ClientSocketPool::CreateConnectJob&lt;/code&gt;&lt;/a&gt; uses a &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/socket/connect_job_factory.h;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;l=34" rel="noopener noreferrer"&gt;&lt;code&gt;ConnectJobFactory&lt;/code&gt;&lt;/a&gt; to create a &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/socket/connect_job.h;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;l=124" rel="noopener noreferrer"&gt;&lt;code&gt;ConnectJob&lt;/code&gt;&lt;/a&gt;, passing along the origin URL (&lt;code&gt;endpoint&lt;/code&gt;) and proxy server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/socket/connect_job_factory.cc;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;l=154" rel="noopener noreferrer"&gt;&lt;code&gt;ConnectJobFactory::CreateConnectJob&lt;/code&gt;&lt;/a&gt; examines the proxy server and, in the case that it's not direct (and HTTP-like, not SOCKS) defers to an &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_proxy_connect_job.h;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;l=92" rel="noopener noreferrer"&gt;&lt;code&gt;HttpProxyConnectJob::Factory&lt;/code&gt;&lt;/a&gt;, which simply creates an &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_proxy_connect_job.h;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;bpv=1;bpt=1;l=89" rel="noopener noreferrer"&gt;&lt;code&gt;HttpProxyConnectJob&lt;/code&gt;&lt;/a&gt;, a subclass of &lt;code&gt;ConnectJob&lt;/code&gt;. This, too, has a large set of states, although only a few are used in this situation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HttpProxyConnectJob -&amp;gt; STATE_BEGIN_CONNECT
HttpProxyConnectJob -&amp;gt; STATE_TRANSPORT_CONNECT
HttpProxyConnectJob -&amp;gt; STATE_TRANSPORT_CONNECT_COMPLETE                                                                                                                                                             
HttpProxyConnectJob -&amp;gt; STATE_HTTP_PROXY_CONNECT
HttpProxyConnectJob -&amp;gt; STATE_HTTP_PROXY_CONNECT_COMPLETE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checking the implementation of those states, &lt;code&gt;STATE_TRANSPORT_CONNECT&lt;/code&gt; involves creating a &lt;code&gt;TransportConnectJob&lt;/code&gt; (since the connection to &lt;code&gt;localhost:8080&lt;/code&gt; is not using HTTPS). But at this point my head is starting to spin at the number of nested "jobs", so I'll stop here and assume that &lt;code&gt;TransportConnectJob::Connect&lt;/code&gt; does what it says on the tin: connects to the host (the proxy server) specified in the &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_proxy_connect_job.h;drc=58b8aff108cb11d3755f4cc18efa10f971be9682;l=43" rel="noopener noreferrer"&gt;&lt;code&gt;HttpProxySocketParams&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initializing the Connection
&lt;/h3&gt;

&lt;p&gt;The next state, &lt;code&gt;STATE_HTTP_PROXY_CONNECT&lt;/code&gt;, wraps the socket returned from the &lt;code&gt;TransportConnectJob&lt;/code&gt; in an &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_proxy_client_socket.h;l=38?q=HttpProxyClientSocket" rel="noopener noreferrer"&gt;&lt;code&gt;HttpProxyClientSocket&lt;/code&gt;&lt;/a&gt; and calls its &lt;code&gt;Connect&lt;/code&gt; method. And no surprise, there's another state machine here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HttpProxyClientSocket -&amp;gt; STATE_GENERATE_AUTH_TOKEN
HttpProxyClientSocket -&amp;gt; STATE_GENERATE_AUTH_TOKEN_COMPLETE
HttpProxyClientSocket -&amp;gt; STATE_SEND_REQUEST
HttpProxyClientSocket -&amp;gt; STATE_SEND_REQUEST_COMPLETE
HttpProxyClientSocket -&amp;gt; STATE_READ_HEADERS
HttpProxyClientSocket -&amp;gt; STATE_READ_HEADERS_COMPLETE                                                                                                                                                                                                                                                                                                                                                                                                                                                     
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're not using proxy authentication (which is an additional complication sprinkled evenly over this entire stack!), so the interesting state here is &lt;code&gt;STATE_SEND_REQUEST&lt;/code&gt;. &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_proxy_client_socket.cc;l=337?q=net%2Fhttp%2Fhttp_proxy_client_socket.cc" rel="noopener noreferrer"&gt;This&lt;/a&gt; calls out to the &lt;code&gt;ProxyDelegate&lt;/code&gt;, if one is configured, and then calls &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/proxy_client_socket.cc;drc=f3ee53147a677fb8d5fac5a83e68a41041c66758;l=25" rel="noopener noreferrer"&gt;&lt;code&gt;ProxyClientSocket::BuildTunnelRequest&lt;/code&gt;&lt;/a&gt; which &lt;em&gt;finally&lt;/em&gt; does something recognizable: creates a "CONNECT" request line, with the host and port for the endpoint (so, &lt;code&gt;CONNECT ip.cow.org:443 HTTP/1.1&lt;/code&gt; in this example).&lt;/p&gt;

&lt;p&gt;The next state is &lt;code&gt;STATE_READ_HEADERS&lt;/code&gt;, which reads the response from the proxy. If that's a 200 OK, then the socket is connected &lt;em&gt;through&lt;/em&gt; the proxy and to the endpoint, and from here on out can be treated just like a socket connected directly to the endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Re-Surfacing
&lt;/h3&gt;

&lt;p&gt;So, let's trace the result back up through the stack. The interleaving of the logging added above helps quite a bit here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HttpProxyConnectJob -&amp;gt; STATE_HTTP_PROXY_CONNECT_COMPLETE
HttpStreamFactory::Job -&amp;gt; STATE_INIT_CONNECTION_COMPLETE
HttpStreamFactory::Job -&amp;gt; STATE_CREATE_STREAM
HttpStreamFactory::Job -&amp;gt; STATE_CREATE_STREAM_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_CREATE_STREAM_COMPLETE
HttpNetworkTransaction -&amp;gt; STATE_CONNECTED_CALLBACK
[0926/173834.596927:ERROR:churl_bin.cc(89)] OnConnected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;STATE_HTTP_PROXY_CONNNECT_COMPLETE&lt;/code&gt; calls the parent class's &lt;code&gt;SetSocket&lt;/code&gt; to use the socket prepared earlier.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HttpStreamFactory::Job&lt;/code&gt; gets the result wrapped in a &lt;code&gt;ClientSocketHandle&lt;/code&gt;. As always, it handles a half-dozen concerns in &lt;code&gt;STATE_INIT_CONNECTION_COMPLETE&lt;/code&gt;, then wraps that in an &lt;code&gt;HttpBasicStream&lt;/code&gt; in &lt;code&gt;STATE_CREATE_STREAM&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;HttpNetworkTransaction&lt;/code&gt; &lt;code&gt;STATE_CREATE_STREAM_COMPLETE&lt;/code&gt; then calls the &lt;code&gt;OnConnected&lt;/code&gt; callback, which results in a debug log message in &lt;code&gt;churl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;From that point, there's no further special handling of proxies -- this is a socket carrying an HTTP stream, like any other.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;This will be the last post on this topic -- I've learned the things I wanted to learn already. However, there are certainly more things to explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What happens when making a simple proxy request, rather than tunneled?&lt;/li&gt;
&lt;li&gt;What happens when a proxy tunnel fails?&lt;/li&gt;
&lt;li&gt;What happens when a proxy requires authentication and the browser must prompt the user?&lt;/li&gt;
&lt;li&gt;What happens when a proxy implements QUIC?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these are handled somewhere in the stack, but I've skipped over them to try to reduce the breadth of knowledge I had to understand. And it was still quite broad!&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>chromium</category>
    </item>
    <item>
      <title>ffizz: Build a Beautiful C API in Rust</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Tue, 20 Jun 2023 01:56:24 +0000</pubDate>
      <link>https://dev.to/djmitche/ffizz-build-a-beautiful-c-api-in-rust-4g0e</link>
      <guid>https://dev.to/djmitche/ffizz-build-a-beautiful-c-api-in-rust-4g0e</guid>
      <description>&lt;p&gt;Foreign Function Interface, FFI, is an umbrella term for interfacing between programming languages. Most languages support a way to interface with C: C-style function calls, C-compatible memory layouts for data types, and so on. Interfacing two languages that are not C -- for example, Python to Rust -- typically involves gluing both languages together with some C code.&lt;/p&gt;

&lt;p&gt;The choice of C as the &lt;em&gt;lingua franca&lt;/em&gt; for communication between modern programming languages is, I think, one of the great tragedies of the history of computing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rust FFI Today
&lt;/h2&gt;

&lt;p&gt;Rust supports two kinds of FFI: calling into Rust from another language; and calling into another language from Rust. Most of the thought and tooling that exists right now is organized around the second kind. For example, &lt;a href="https://rust-lang.github.io/rust-bindgen/" rel="noopener noreferrer"&gt;bindgen&lt;/a&gt; is a popular tool that generates useful Rust wrappers from a C or C++ header file.&lt;/p&gt;

&lt;p&gt;The tooling for the first kind -- calling Rust from another language -- is a bit less developed, and tends to rely on code generation that doesn't necessarily produce a natural C API. &lt;a href="https://github.com/mozilla/cbindgen/blob/master/docs.md" rel="noopener noreferrer"&gt;&lt;code&gt;cbindgen&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://mozilla.github.io/uniffi-rs/" rel="noopener noreferrer"&gt;&lt;code&gt;uniffi&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://cxx.rs/" rel="noopener noreferrer"&gt;&lt;code&gt;cxx&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://rust-diplomat.github.io/book/" rel="noopener noreferrer"&gt;Diplomat&lt;/a&gt; all take this course.&lt;/p&gt;

&lt;h2&gt;
  
  
  Natural C APIs
&lt;/h2&gt;

&lt;p&gt;It gets a bad reputation, but C can actually be a pleasure to write, when using a nicely designed API. For example, &lt;a href="https://curl.se/libcurl/c/" rel="noopener noreferrer"&gt;&lt;code&gt;libcurl&lt;/code&gt;&lt;/a&gt; provides a C API to support making HTTP requests from C. It's carefully and thoughtfully designed to minimize surprises and make correct usage easy. See, for example, &lt;a href="https://curl.se/libcurl/c/curl_slist_append.html" rel="noopener noreferrer"&gt;&lt;code&gt;curl_slist_append&lt;/code&gt;&lt;/a&gt;, a succinct, efficient tool for creating lists of strings to pass to the API.&lt;/p&gt;

&lt;p&gt;I don't know of any authoritative document, but in my experience good C APIs have a few properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allocate and free functions, for each type. In &lt;code&gt;libcurl&lt;/code&gt;, these are &lt;a href="https://curl.se/libcurl/c/curl_easy_init.html" rel="noopener noreferrer"&gt;&lt;code&gt;curl_easy_init&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://curl.se/libcurl/c/curl_easy_cleanup.html" rel="noopener noreferrer"&gt;&lt;code&gt;curl_easy_cleanup&lt;/code&gt;&lt;/a&gt;. A C programmer will know that they must allocate a new object before using it, and that once that object is freed, it cannot be used again.&lt;/li&gt;
&lt;li&gt;An "owner" for every allocated object, responsible for freeing it and making sure it isn't freed while still in use. Ownership semantics are usually described in comments.&lt;/li&gt;
&lt;li&gt;Integer return values with negative numbers signaling an error and zero or positive values indicating success.&lt;/li&gt;
&lt;li&gt;Selective use of "output parameters" to support functions that have multiple results. For example, &lt;code&gt;int query_execute(query_t *query, rowset_t **rowset_out)&lt;/code&gt; probably returns a negative error or positive number of rows matching the query, and writes a pointer to a newly allocated &lt;code&gt;rowset_t&lt;/code&gt; in &lt;code&gt;*rowset_out&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Clear documentation of thread safety: what functions can be called concurrently, and what data structures can be accessed from multiple threads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, the Rust FFI tools mentioned above do not generate a very natural C API. At best, they generate a C interface to the Rust API, with the expectation that the C developer will understand both the Rust API and how it is represented in C.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going it Alone
&lt;/h2&gt;

&lt;p&gt;The alternative is to forget about the tools and create the perfect API by hand. This is not easy!&lt;/p&gt;

&lt;p&gt;You'll need to write a C header file, complete with types, function declarations, and extensive documentation comments.&lt;/p&gt;

&lt;p&gt;Then you'll need to implement those functions in Rust with &lt;code&gt;extern "C"&lt;/code&gt;, and write Rust &lt;code&gt;struct&lt;/code&gt; definitions to match the C types. Careful: nothing verifies that the header declarations and Rust function and type signatures match, and type layouts differ across architectures.&lt;/p&gt;

&lt;p&gt;You'll also need to ensure that the C API does not create undefined behavior for the Rust code. All of those &lt;code&gt;extern "C"&lt;/code&gt; functions are &lt;code&gt;unsafe&lt;/code&gt;, after all. This usually involves writing clear but concise instructions in the header, and then convincing yourself that any C code satisfying those instructions maintains the invariants of the Rust code.&lt;/p&gt;

&lt;p&gt;I set out on this course with &lt;a href="https://github.com/GothenburgBitFactory/taskwarrior/tree/develop/taskchampion/lib" rel="noopener noreferrer"&gt;taskchampion-lib&lt;/a&gt; about three years ago. It quickly became clear that some tooling would help. &lt;/p&gt;

&lt;h2&gt;
  
  
  Ffizz
&lt;/h2&gt;

&lt;p&gt;Thus was born &lt;a href="https://docs.rs/ffizz/latest/ffizz/" rel="noopener noreferrer"&gt;&lt;em&gt;ffizz&lt;/em&gt;&lt;/a&gt;. This is a collection of tools for building natural C APIs in Rust.&lt;/p&gt;

&lt;p&gt;The simplest is &lt;a href="https://docs.rs/ffizz-header/latest/ffizz_header/" rel="noopener noreferrer"&gt;&lt;code&gt;ffizz-header&lt;/code&gt;&lt;/a&gt;, which supports building a header file from doc comments in the Rust source. While it's still up to the API designer to ensure that the C and Rust function declarations match, that's much easier when they are just a few lines apart in the same source file.&lt;/p&gt;

&lt;p&gt;Strings are a very common data type, and Rust and C handle them differently, so passing strings back and forth can be a lot of work and is an easy place to introduce bugs.&lt;br&gt;
The &lt;a href="https://docs.rs/ffizz-string/latest/ffizz_string/" rel="noopener noreferrer"&gt;&lt;code&gt;ffizz-string&lt;/code&gt;&lt;/a&gt; crate supplies a &lt;code&gt;FzString&lt;/code&gt; type that manages conversion between types on demand, eliminating a lot of boilerplate and providing simple safety requirements.&lt;/p&gt;

&lt;p&gt;Finally, &lt;a href="https://docs.rs/ffizz-passby/latest/ffizz_passby/" rel="noopener noreferrer"&gt;&lt;code&gt;ffizz-passby&lt;/code&gt;&lt;/a&gt; provides utility types to handle common methods of passing data across C API boundaries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pass-by-value: values are copied as necessary when passed to or returned from functions. This is typically used for Rust types that implement Copy.&lt;/li&gt;
&lt;li&gt;Boxed objects: values that are allocated and freed and always referenced by a pointer. In Rust, these use &lt;code&gt;Box&amp;lt;T&amp;gt;&lt;/code&gt;, while C uses a raw pointer.&lt;/li&gt;
&lt;li&gt;Unboxed objects: values that can be placed on the stack or in another struct. This storage location must be initialized before it is used, and is typically passed to Rust functions as a raw pointer. When the caller is finished with the value, it must be released, leaving the storage uninitialized again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an example, &lt;code&gt;FzString&lt;/code&gt; is an unboxed object: it is up to the C caller to allocate enough space to store the value (which may contain a pointer and two 64-bit integers), initialize the space, and finally call a function like &lt;code&gt;fz_string_free&lt;/code&gt; to free the associated memory when the value is no longer needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give It a Try!
&lt;/h2&gt;

&lt;p&gt;If you've worked on this sort of interface before, please give ffizz a try, even if just experimentally. I've tried to solve general problems and not just what I needed for Taskchampion, but surely my imagination has come up short somehow. Let me know! Leave an issue on GitHub, or ping me on Mastodon at &lt;code&gt;@djmitche@mastodon.social&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ffi</category>
      <category>api</category>
    </item>
    <item>
      <title>Chromium Spelunking: The IO Thread</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Tue, 06 Jun 2023 15:18:28 +0000</pubDate>
      <link>https://dev.to/djmitche/chromium-spelunking-the-io-thread-464n</link>
      <guid>https://dev.to/djmitche/chromium-spelunking-the-io-thread-464n</guid>
      <description>&lt;p&gt;The error at the end of &lt;a href="https://dev.to/djmitche/chromium-spelunking-a-stuck-task-bh4"&gt;the last post&lt;/a&gt; looks like this (I've omitted further lines of backtrace as they're not relevant):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0605/175824.724186:ERROR:churl_bin.cc(190)] URLRequestContext created: 0x7fb224002df0
[0605/175824.725417:ERROR:churl_bin.cc(198)] calling start     
[0605/175824.730763:ERROR:churl_bin.cc(200)] started     
[0605/175824.734067:FATAL:current_thread.cc(197)] Check failed: sequence_manager. 
#0 0x7fb23107ca8c base::debug::CollectStackTrace()
#1 0x7fb2310332da base::debug::StackTrace::StackTrace()                                                
#2 0x7fb231033295 base::debug::StackTrace::StackTrace()       
#3 0x7fb230d575f9 logging::LogMessage::~LogMessage()           
#4 0x7fb230d02bac logging::(anonymous namespace)::DCheckLogMessage::~DCheckLogMessage()
#5 0x7fb230d02bd9 logging::(anonymous namespace)::DCheckLogMessage::~DCheckLogMessage()
#6 0x7fb230d028bd logging::CheckError::~CheckError() 
#7 0x7fb230ed6cc2 base::CurrentIOThread::Get()     
#8 0x7fb232194f2d net::SocketPosix::Connect()                                                            
#9 0x7fb232199906 net::TCPSocketPosix::Connect()                                                         
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at &lt;a href="https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/task/current_thread.cc;l=197;drc=73265a30d5b5a3873dbf3b92f01abc5c2892ece3" rel="noopener noreferrer"&gt;the failing DHCECK&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;CurrentIOThread&lt;/span&gt; &lt;span class="n"&gt;CurrentIOThread&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sequence_manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetCurrentSequenceManagerImpl&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;DCHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sequence_manager&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;DCHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sequence_manager&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;IsType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MessagePumpType&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CurrentIOThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sequence_manager&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;suggests that this is complaining that it's not running in the IO thread. That seems reasonable -- &lt;code&gt;SocketPosix::Connect&lt;/code&gt; is, indeed, an IO operation. &lt;code&gt;URLRequest&lt;/code&gt; is a pretty low-level tool, and other components are generally expected to use &lt;code&gt;URLFetcher&lt;/code&gt; instead. Still, it's notable that &lt;code&gt;URLRequest&lt;/code&gt; documents that all uses &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request.h;l=85;drc=d097a3e9aea0361fe1dbf30c003d20cf6d635320" rel="noopener noreferrer"&gt;must be in the same thread&lt;/a&gt; but not that the thread must be the IO thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  OK, Run It On the IO Thread
&lt;/h2&gt;

&lt;p&gt;I suppose the easiest thing to do is run the whole &lt;code&gt;Fetch&lt;/code&gt; method on the IO thread. It took me some time to figure out how to create an IO thread. I tried using &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:base/test/test_io_thread.h;l=26;drc=63e1f9974bc57b0ca12d790b2a73e5ba7f5cec6e" rel="noopener noreferrer"&gt;&lt;code&gt;TestIOThread&lt;/code&gt;&lt;/a&gt; but it's not defined in non-test cases. However, its implementation is simple enough that I can just duplicate it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt; &lt;span class="n"&gt;io_thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IO Thread"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;CHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;io_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartWithOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MessagePumpType&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
  &lt;span class="n"&gt;io_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task_runner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;PostTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;FROM_HERE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BindOnce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Churl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Fetch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Unretained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;churl&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PlatformThread&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Seconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;                                                                                                                                                                   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Amazingly, the request completes!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0605/193023.588918:ERROR:churl_bin.cc(68)] OnConnected
[0605/193025.549050:ERROR:churl_bin.cc(144)] OnResponseStarted
[0605/193025.549318:ERROR:churl_bin.cc(154)] Read completed immediately
[0605/193025.549342:ERROR:churl_bin.cc(170)] OnReadCompleted with 281 bytes_read
[0605/193025.549373:ERROR:churl_bin.cc(172)] GOT: {
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip, deflate", 
    "Host": "httpbin.org", 
    "User-Agent": "Dustin's Experiment", 
    "X-Amzn-Trace-Id": "Root=1-647e37cf-251697116275c21857a3f844"
  }, 
  "origin": "34.86.234.200", 
  "url": "http://httpbin.org/get"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So that's pretty cool! 🥳&lt;/p&gt;

&lt;h2&gt;
  
  
  A Bad Ending
&lt;/h2&gt;

&lt;p&gt;Unfortunately, once that 5-second sleep expires:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0605/193351.314239:FATAL:thread_checker.cc(21)] Check failed: checker.CalledOnValidThread(&amp;amp;bound_at). 
#0 0x7fa54a87ca8c base::debug::CollectStackTrace()
#1 0x7fa54a8332da base::debug::StackTrace::StackTrace()
#2 0x7fa54a833295 base::debug::StackTrace::StackTrace()
#3 0x7fa54a5575f9 logging::LogMessage::~LogMessage()
#4 0x7fa54a502bac logging::(anonymous namespace)::DCheckLogMessage::~DCheckLogMessage()
#5 0x7fa54a502bd9 logging::(anonymous namespace)::DCheckLogMessage::~DCheckLogMessage()
#6 0x7fa54a5028bd logging::CheckError::~CheckError()
#7 0x7fa54a7b9029 base::ScopedValidateThreadChecker::ScopedValidateThreadChecker()
#8 0x7fa54b89bdeb net::URLRequest::~URLRequest()
#9 0x7fa54b89c229 net::URLRequest::~URLRequest()
#10 0x55723b34422c std::__Cr::default_delete&amp;lt;&amp;gt;::operator()()
#11 0x55723b34414a std::__Cr::unique_ptr&amp;lt;&amp;gt;::reset()
#12 0x55723b343759 std::__Cr::unique_ptr&amp;lt;&amp;gt;::~unique_ptr()
#13 0x55723b3415aa Churl::~Churl()
#14 0x55723b340ccd main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So &lt;code&gt;main&lt;/code&gt; is returning, at which point it destroys the &lt;code&gt;Churl&lt;/code&gt; instance, which is destroying the &lt;code&gt;URLRequest&lt;/code&gt; instance, which was created on the IO thread. Chromium generally expects objects to be used (and destroyed) in a single thread, and that's what the thread-checker is checking.&lt;/p&gt;

&lt;p&gt;I suspect that one way to fix this would be to refactor things so that the &lt;code&gt;Churl&lt;/code&gt; instance is destroyed on the IO thread. But that actually doesn't sound like a very interesting challenge -- it's probably easiest in this experiment to just call &lt;code&gt;exit(0)&lt;/code&gt; when the fetch is done (in &lt;code&gt;OnReadComplete&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;By the way, I wondered if I could drop the thread pool now that everything's in the IO thread. But, no, at least one thing involved in fetching a URL requires a thread pool - &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/dns/loopback_only.cc;l=130;drc=6e5518d89c7670a231a4c34835a71e7da17a00d1" rel="noopener noreferrer"&gt;&lt;code&gt;net::RunHaveOnlyLoopbackAddressesJob&lt;/code&gt;&lt;/a&gt;. So, we'll need both.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;So, we've successfully fetched a URL (and learned some stuff along the way). If you'd like to see the code, it's in &lt;a href="https://chromium-review.googlesource.com/c/chromium/src/+/4518897/4/net/tools/churl_bin.cc" rel="noopener noreferrer"&gt;this CL&lt;/a&gt;. It's not pretty, and please don't emulate it, but maybe it helps clarify something in one of these posts that wasn't clear.&lt;/p&gt;

&lt;p&gt;Next up, I'd like to start learning how proxies are used in this process. That will involve a new delegate, at least. Once I've got a basic HTTP proxy working, I'll want to experiment with various HTTP versions inside and outside of the proxy (HTTP/2 over HTTP/3, etc.).&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>chromium</category>
    </item>
    <item>
      <title>Chromium Spelunking: A Stuck Task</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Mon, 05 Jun 2023 18:03:53 +0000</pubDate>
      <link>https://dev.to/djmitche/chromium-spelunking-a-stuck-task-bh4</link>
      <guid>https://dev.to/djmitche/chromium-spelunking-a-stuck-task-bh4</guid>
      <description>&lt;p&gt;The &lt;a href="https://dev.to/djmitche/chromium-spelunking-threads-and-tasks-21hm"&gt;last installment&lt;/a&gt; was a bit of a detour from our task -- fetching a URL. But, it was a deliberate one, to learn about things I didn't understand well enough. Before that, I had gotten &lt;code&gt;churl&lt;/code&gt; up to the point where it crashed because its delegate was NULL. So, let's give it a delegate!&lt;/p&gt;

&lt;h2&gt;
  
  
  Delegates
&lt;/h2&gt;

&lt;p&gt;Delegates are a common pattern in Chromium, forming a way for lower-level code to interact with higher-level code. It's a kind of &lt;a href="https://www.chromium.org/developers/design-documents/cookbook/#dependency-inversion" rel="noopener noreferrer"&gt;dependency inversion&lt;/a&gt;. For example, an embedder like Chrome or Fuchsia provides a delegate (several, in fact) to the content layer, which that content layer uses to call back for embedder-related features like autofill.&lt;/p&gt;

&lt;p&gt;In this case, we're providing a delegate to the &lt;code&gt;URLRequest&lt;/code&gt;, a subclass of &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request.h;l=115;drc=d097a3e9aea0361fe1dbf30c003d20cf6d635320" rel="noopener noreferrer"&gt;&lt;code&gt;net::URLRequest::Delegate&lt;/code&gt;&lt;/a&gt;. Happily, most of the methods have default implementations, and in fact the only &lt;em&gt;required&lt;/em&gt; method is &lt;code&gt;OnReadCompleted&lt;/code&gt;.  My delegate overrides that method as well as &lt;code&gt;OnConnected&lt;/code&gt; and &lt;code&gt;OnResponseReceived&lt;/code&gt;, just to log when those events occur. In fact, I copied from &lt;a href="https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:net/url_request/url_request_test_util.h;l=97;drc=02199fc586b3af08fee6a7b188d731f381cd814c" rel="noopener noreferrer"&gt;&lt;code&gt;TestDelegate&lt;/code&gt;&lt;/a&gt;, including the &lt;code&gt;buf_&lt;/code&gt; stuff and the &lt;code&gt;Read&lt;/code&gt; calls.&lt;/p&gt;

&lt;p&gt;So, at this point I have a delegate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChurlDelegate&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;URLRequest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Delegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nl"&gt;public:&lt;/span&gt;
  &lt;span class="n"&gt;ChurlDelegate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;buf_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MakeRefCounted&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IOBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kBufferSize&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;ChurlDelegate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;OnConnected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;URLRequest&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TransportInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CompletionOnceCallback&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"OnConnected"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;URLRequest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Delegate&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;OnConnected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;OnResponseStarted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;URLRequest&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;net_error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"OnResponseStarted"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net_error&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Error: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;net_error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                                                                                                                                                                                                      
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: print response and headers?&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;bytes_read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;kBufferSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes_read&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Read completed immediately"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;OnReadCompleted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes_read&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes_read&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ERR_IO_PENDING&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Error from READ: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;bytes_read&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;OnReadCompleted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;URLRequest&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;bytes_read&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"OnReadCompleted with "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;bytes_read&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;" bytes_read"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"GOT: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;buf_&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;                                                                                                                                                                      
      &lt;span class="n"&gt;bytes_read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;kBufferSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes_read&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;scoped_refptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IOBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buf_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the Churl class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Churl&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nl"&gt;public:&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Fetch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;URLRequestContextBuilder&lt;/span&gt; &lt;span class="n"&gt;url_request_context_builder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;url_request_context_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_user_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dustin's Experiment"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;url_request_context_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_proxy_config_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProxyConfigServiceDirect&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;url_request_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url_request_context_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;url_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url_request_context&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;CreateRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;GURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://httpbin.org/get"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// TODO: get this from command line&lt;/span&gt;
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RequestPriority&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;HIGHEST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;delegate_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                                                                                                                                                                                
        &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NetworkTrafficAnnotationTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;MutableNetworkTrafficAnnotationTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TRAFFIC_ANNOTATION_FOR_TESTS&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"calling start"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;url_request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"started"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;URLRequestContext&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;url_request_context_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;ChurlDelegate&lt;/span&gt; &lt;span class="n"&gt;delegate_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and all of this created in &lt;code&gt;main&lt;/code&gt; with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;  &lt;span class="n"&gt;Churl&lt;/span&gt; &lt;span class="n"&gt;churl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPool&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CreateSingleThreadTaskRunner&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;PostTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;FROM_HERE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BindOnce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Churl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Fetch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Unretained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;churl&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the delegate is passed to &lt;code&gt;CreateRequest&lt;/code&gt; as a raw pointer. It's up to me to make sure that the delegate continues to exist for the duration of that request, and it will crash otherwise. Ask me how I know!&lt;/p&gt;

&lt;p&gt;I put it into an instance variable in &lt;code&gt;Churl&lt;/code&gt;, since that &lt;code&gt;Churl&lt;/code&gt; instance lives until the end of &lt;code&gt;main&lt;/code&gt;. The receiver for the &lt;code&gt;Fetch&lt;/code&gt; method needs to be included in the task callback, and that's done with &lt;code&gt;base::Unretained&lt;/code&gt; to indicate that the callback does not "own" the pointer.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Easy Fix
&lt;/h2&gt;

&lt;p&gt;So, the first run fails with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0525/191840.310712:FATAL:command_line.cc(247)] Check failed: current_process_commandline_. 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A little exploring of other "utility" tools like &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/tools/root_store_tool/root_store_tool.cc;bpv=1;bpt=0" rel="noopener noreferrer"&gt;&lt;code&gt;root_store_tool&lt;/code&gt;&lt;/a&gt; suggests&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CommandLine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                                                                                                                                                                             
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And indeed, this gets things running -- sort of.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0530/190907.523753:ERROR:churl_bin.cc(190)] URLRequestContext created: 0x7f4874003780
[0530/190907.524119:ERROR:churl_bin.cc(198)] calling start    
[0530/190907.526291:ERROR:churl_bin.cc(200)] started           
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it -- no logging from &lt;code&gt;OnConnected&lt;/code&gt;. Maybe not so easy?&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding a Stuck Task
&lt;/h2&gt;

&lt;p&gt;I am sort of old-fashioned, and I'd rather debug things by running them and watching the output, than using fancy tools like &lt;code&gt;lldb&lt;/code&gt;. My usual tactic is to add lots of debug logging (in Chromium, &lt;code&gt;DLOG(ERROR) &amp;lt;&amp;lt; "got here 1"&lt;/code&gt;) to narrow down where a problem occurs. In this case, &lt;code&gt;Start()&lt;/code&gt; started things off, but got "stuck" somewhere.&lt;/p&gt;

&lt;p&gt;Looking at &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request.cc;l=536;drc=cf7d13faa2b8a7530c261ca512fcbd0869ed2523" rel="noopener noreferrer"&gt;&lt;code&gt;URLRequest::Start&lt;/code&gt;&lt;/a&gt;, it creates a new job with a job factory, and I can verify that it does, indeed call &lt;code&gt;StartJob(..)&lt;/code&gt; with this new job by adding a debug print after that line.&lt;/p&gt;

&lt;p&gt;That job is a subclass of &lt;code&gt;URLRequestJob&lt;/code&gt;, but which subclass? Codesearch gives a list of subclasses, and &lt;code&gt;URLRequestHttpJob&lt;/code&gt; seems a likely suspect. Adding some debug prints there confirms this guess. &lt;code&gt;URLRequestJob&lt;/code&gt; then calls &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request_http_job.cc;l=252;drc=6bfd45d97e9a780d2d5a6f04be930131848eb0b2" rel="noopener noreferrer"&gt;&lt;code&gt;job-&amp;gt;Start()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;URLRequestHttpJob&lt;/code&gt; does its work in a series of callback tasks. Each possible bit of work is a separate method, and any conditionals or loops are accomplished "manually" by conditionally calling or posting a task for a different method. It's almost like assembly language, tracing out all of the conditional jumps and control-flow cycles. In this case, adding debug prints to the beginning of each method quickly shows that &lt;a href="https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:net/url_request/url_request_http_job.cc;l=537;drc=c4efcabd32a851d4d7816206d3c8793a55e9d57e" rel="noopener noreferrer"&gt;&lt;code&gt;StartTransactionInternal&lt;/code&gt;&lt;/a&gt; is the last method called.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;HttpRequestJob::Start&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;StartTransactionInternal&lt;/code&gt; method seems to set up a transaction and call its &lt;code&gt;Start&lt;/code&gt; method with a callback bound to &lt;code&gt;URLRequestHttpJob::OnStartCompleted&lt;/code&gt;. If the &lt;code&gt;Start&lt;/code&gt; method finishes immediately, it calls &lt;code&gt;OnStartCompleted&lt;/code&gt; directly. This answers my question from &lt;a href="https://dev.to/djmitche/chromium-spelunking-getting-started-n84#big-picture"&gt;the first post&lt;/a&gt;: when a function takes a callback, but does not return &lt;code&gt;ERR_IO_PENDING&lt;/code&gt;, it also does not invoke the callback and expects its caller to do so. This seems like it would be a source of bugs, if one of those two control-flow paths is rarely taken.&lt;/p&gt;

&lt;p&gt;Anyway, &lt;code&gt;OnStartCompleted&lt;/code&gt; is never called, and one more debug print shows that &lt;code&gt;Start&lt;/code&gt; is returning &lt;code&gt;ERR_IO_PENDING&lt;/code&gt; so &lt;code&gt;Start&lt;/code&gt; should be calling it.&lt;/p&gt;

&lt;p&gt;I briefly wondered if this was another problem with &lt;a href="https://dev.to/djmitche/chromium-spelunking-threads-and-tasks-21hm"&gt;threads and tasks&lt;/a&gt;, where the process was exiting before the task had a chance to run. Maybe &lt;code&gt;FlushForTesting&lt;/code&gt; sees no tasks running while some kind of IO is pending, and returns? I added a sleep in the main task (&lt;code&gt;base::PlatformThread::Sleep(base::Seconds(5))&lt;/code&gt;) and &lt;code&gt;OnStartCompleted&lt;/code&gt; still did not run, so it's nothing quite that simple.&lt;/p&gt;

&lt;p&gt;So let's dive one layer deeper. &lt;code&gt;URLRequestHttpJob&lt;/code&gt; is using a factory to make an instance of an interface, in this case an &lt;code&gt;HttpTransactionFactory&lt;/code&gt; creating an &lt;code&gt;HttpTransaction&lt;/code&gt;.There's no easy way to print the class name of an object, but codesearch can (usually) list the subclasses of an interface, so a bit of guess-and-check works. My first guess was an &lt;code&gt;HttpNetworkTransaction&lt;/code&gt;, but a debug print in its &lt;code&gt;Start&lt;/code&gt; method did not appear. Then I remembered that the &lt;code&gt;HttpCache&lt;/code&gt; is a "read-through" cache, and a debug print confirms that the &lt;code&gt;HttpTransaction&lt;/code&gt; is an &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/http/http_cache_transaction.h;l=53" rel="noopener noreferrer"&gt;&lt;code&gt;HttpCache::Transaction&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;HttpTransaction::Start&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;HttpCache::Transaction&lt;/code&gt; class uses the &lt;a href="https://chromium.googlesource.com/chromium/src/+/master/net/docs/code-patterns.md#doloop" rel="noopener noreferrer"&gt;DoLoop pattern&lt;/a&gt;. I used a quick vim macro to print the states as they occurred:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0525/195452.887052:ERROR:http_cache_transaction.cc(861)] STATE_GET_BACKEND
[0525/195452.887096:ERROR:http_cache_transaction.cc(866)] STATE_GET_BACKEND_COMPLETE
[0525/195452.887189:ERROR:http_cache_transaction.cc(870)] STATE_INIT_ENTRY
[0525/195452.887230:ERROR:http_cache_transaction.cc(875)] STATE_OPEN_OR_CREATE_ENTRY
[0525/195452.887406:ERROR:http_cache_transaction.cc(880)] STATE_OPEN_OR_CREATE_ENTRY_COMPLETE
[0525/195452.887450:ERROR:http_cache_transaction.cc(902)] STATE_ADD_TO_ENTRY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, it's stuck after &lt;code&gt;DoAddToEntry&lt;/code&gt;. More debug prints there show that it's returning the &lt;code&gt;rv&lt;/code&gt; from &lt;code&gt;cache_-&amp;gt;AddTransactionToEntry&lt;/code&gt;. &lt;code&gt;cache_&lt;/code&gt; is an &lt;code&gt;HttpCache&lt;/code&gt;, so off we go!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;HttpCache::AddTransactionToEntry&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// Adds a transaction to an ActiveEntry. This method returns ERR_IO_PENDING&lt;/span&gt;
  &lt;span class="c1"&gt;// and the transaction will be notified about completion via its IO callback.&lt;/span&gt;
  &lt;span class="c1"&gt;// In a failure case, the callback will be invoked with ERR_CACHE_RACE.&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;AddTransactionToEntry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ActiveEntry&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Transaction&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, what's the transaction's "IO callback" in this case? It has an &lt;code&gt;io_callback_&lt;/code&gt; property, and elsewhere in &lt;code&gt;http_cache.cc&lt;/code&gt; I see &lt;code&gt;transaction-&amp;gt;io_callback().Run(OK)&lt;/code&gt; so at a guess that's what it's calling. But, what is that set to at the time? The &lt;code&gt;HttpCache::Transaction&lt;/code&gt; constructor sets this to a binding for the &lt;code&gt;OnIOComplete&lt;/code&gt; method, and it seems it's only set to other things in order to support testing. And that just calls &lt;code&gt;DoLoop&lt;/code&gt;. And that would log. So, what's going on in the cache that causes it not to call the IO callback?&lt;/p&gt;

&lt;p&gt;Adding some &lt;em&gt;more&lt;/em&gt; debug prints to &lt;code&gt;HttpCache&lt;/code&gt;, it seems that &lt;a href="https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:net/http/http_cache.cc;l=1105;drc=b192722970ae854473585f077ed7dd489885e4fd" rel="noopener noreferrer"&gt;&lt;code&gt;ProcessQueuedTransactions&lt;/code&gt;&lt;/a&gt; is executing, and posting a task, but &lt;code&gt;HttpCache::OnProcessQueuedTransactions&lt;/code&gt; never executes.&lt;/p&gt;

&lt;p&gt;I got stuck here for a bit, and decided I'd put in enough work to ask for help.  Pairing with a colleague, we pored over the code, looking for what I might have missed. Nothing jumped out as obviously wrong.&lt;/p&gt;

&lt;p&gt;As an experiment, we tried posting another task that just contained a lambda expression logging a message. That task ran! So, this isn't an issue of the thread pool not running tasks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SingleThreadTaskRunner&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GetCurrentDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;PostTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;FROM_HERE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BindOnce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;HttpCache&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;OnProcessQueuedTransactions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GetWeakPtr&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                     &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;UnsafeDanglingUntriaged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;GetWeakPtr()&lt;/code&gt; in the &lt;code&gt;PostTask&lt;/code&gt; invocation is curious, though -- what happens if that pointer becomes invalid before the task runs? Replacing it with &lt;code&gt;base::Unretained(this)&lt;/code&gt; "fixes" the issue: the callback gets called. So it seems like the task machinery detects that a weak pointer has been invalidated and drops the task depending on it -- a pretty smart way to avoid use-after-free errors! That means that the &lt;code&gt;HttpCache&lt;/code&gt; is getting destroyed before this callback can begin.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;HttpCache&lt;/code&gt; Lifetime
&lt;/h3&gt;

&lt;p&gt;So, let's see if we can figure out what's creating that and how long it lasts. It looks like &lt;code&gt;HttpCache&lt;/code&gt; is a subclass of &lt;code&gt;HttpTransactionFactory&lt;/code&gt;, and the &lt;code&gt;URLRequestContext&lt;/code&gt; references it as &lt;code&gt;http_transaction_factory_&lt;/code&gt;. That's &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request_context_builder.cc;l=519?q=URLRequestContextBuilder&amp;amp;ss=chromium%2Fchromium%2Fsrc" rel="noopener noreferrer"&gt;set by &lt;code&gt;URLRequestContextBuilder&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ah, the &lt;code&gt;URLRequestContext&lt;/code&gt; is in a local variable so it is being destroyed while the &lt;code&gt;URLRequest&lt;/code&gt; is still in progress. So that's no good. Rearranging things to keep the context as an instance variable of the &lt;code&gt;Churl&lt;/code&gt; class fixes the issue.&lt;/p&gt;

&lt;p&gt;Which is not to say it's working, but that's a job for the next post in the series:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0605/175824.724186:ERROR:churl_bin.cc(190)] URLRequestContext created: 0x7fb224002df0
[0605/175824.725417:ERROR:churl_bin.cc(198)] calling start     
[0605/175824.730763:ERROR:churl_bin.cc(200)] started     
[0605/175824.734067:FATAL:current_thread.cc(197)] Check failed: sequence_manager. 
#0 0x7fb23107ca8c base::debug::CollectStackTrace()
#1 0x7fb2310332da base::debug::StackTrace::StackTrace()                                                
#2 0x7fb231033295 base::debug::StackTrace::StackTrace()       
#3 0x7fb230d575f9 logging::LogMessage::~LogMessage()           
#4 0x7fb230d02bac logging::(anonymous namespace)::DCheckLogMessage::~DCheckLogMessage()
#5 0x7fb230d02bd9 logging::(anonymous namespace)::DCheckLogMessage::~DCheckLogMessage()
#6 0x7fb230d028bd logging::CheckError::~CheckError() 
#7 0x7fb230ed6cc2 base::CurrentIOThread::Get()     
#8 0x7fb232194f2d net::SocketPosix::Connect()                                                            
#9 0x7fb232199906 net::TCPSocketPosix::Connect()                                                         
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[update: it turns out it's also necessary to keep the &lt;code&gt;URLRequest&lt;/code&gt; in an instance variable]&lt;/p&gt;

</description>
      <category>chromium</category>
      <category>cpp</category>
    </item>
    <item>
      <title>Chromium Spelunking: Threads and Tasks</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Thu, 18 May 2023 00:10:02 +0000</pubDate>
      <link>https://dev.to/djmitche/chromium-spelunking-threads-and-tasks-21hm</link>
      <guid>https://dev.to/djmitche/chromium-spelunking-threads-and-tasks-21hm</guid>
      <description>&lt;p&gt;In the last post, I "solved" a problem with incorrect usage of task runners, but I still don't feel like I &lt;em&gt;understand&lt;/em&gt; how these things work. I happen to have this simple little binary with few moving pieces, so this seemed like a good time to try to learn a bit more.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Question
&lt;/h2&gt;

&lt;p&gt;I have the following code, which is working fine (meaning it crashes because there's no delegate):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPoolInstance&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CreateAndStartWithDefaultParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"churl"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;task_runner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPool&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CreateSingleThreadTaskRunner&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TaskPriority&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;USER_VISIBLE&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="n"&gt;task_runner&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;PostTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FROM_HERE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BindOnce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://chromium.googlesource.com/chromium/src/+/HEAD/docs/threading_and_tasks.md#Posting-via-a-TaskRunner" rel="noopener noreferrer"&gt;"Threading and Tasks"&lt;/a&gt; document says&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A task that can run on any thread and doesn’t have ordering or mutual exclusion requirements with other tasks should be posted using one of the &lt;code&gt;base::ThreadPool::PostTask*()&lt;/code&gt; functions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My &lt;code&gt;Task()&lt;/code&gt; is such a task, so I tried changing the last line to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPool&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PostTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FROM_HERE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BindOnce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fails. When run directly, it fails with a SIGSEGV from a NULL pointer, but when run under gdb it fails with the familiar &lt;code&gt;Check failed: has_sequenced_context || !post_task_success.&lt;/code&gt; I don't know why this doesn't appear when run directly -- maybe the SIGSEGV occurs while trying to print the message? But I'll let that mystery remain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep Background
&lt;/h2&gt;

&lt;p&gt;So, I've misunderstood something here. Perhaps it's time to just start gathering information in hopes I can piece together the big picture. I did this in &lt;a href="https://dev.to/djmitche/chromium-spelunking-getting-started-n84"&gt;the first post in the series&lt;/a&gt;, but this time I won't include all of my findings inline. &lt;/p&gt;

&lt;p&gt;However, my process may be interesting. I began with another re-read of &lt;a href="https://chromium.googlesource.com/chromium/src/+/HEAD/docs/threading_and_tasks.md#Posting-via-a-TaskRunner" rel="noopener noreferrer"&gt;"Threading and Tasks"&lt;/a&gt;, this time jotting down a few notes for each section but more importantly keeping a running list of questions. As I came across an answer to a question, I'd include that in the notes and cross off the question. I find that this helps me to focus my thinking a little bit: when I have a question, I can write it down and set it aside; and when I find new information, I can compare it to the list of questions in case it answers one or two.&lt;/p&gt;

&lt;p&gt;It also means that, after working for a while, any remaining questions on the list are good questions to ask someone with more expertise.&lt;/p&gt;

&lt;p&gt;Here's a partial list of questions I jotted down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why does &lt;code&gt;base::ThreadPool::PostTask&lt;/code&gt; fail?&lt;/li&gt;
&lt;li&gt;What is a "Sequence" and how is it different from a "Virtual Thread"?&lt;/li&gt;
&lt;li&gt;Can there be multiple task queues per thread?&lt;/li&gt;
&lt;li&gt;How are tasks from multiple queues in a thread handled?&lt;/li&gt;
&lt;li&gt;When a function takes a callback or delegates, what runner/queue does it use to call those?&lt;/li&gt;
&lt;li&gt;How do the &lt;code&gt;PostTask..AndReply&lt;/code&gt; methods work?&lt;/li&gt;
&lt;li&gt;If there is one SequenceManager per thread, how do thread pools work? Are there multiple SequenceManagers all competing for tasks from the same TaskQueue?&lt;/li&gt;
&lt;li&gt;How do the "current defaults" work for SequencedTaskRunner and SingleThreadTaskRunner?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I finished reading the document, I started looking at the code itself. I've learned that, in general, this is the slowest way to learn things about Chromium: most source files are sparsely commented and not ordered in a way that helps a newcomer to understand them. I suspect IDEs make this worse, especially in &lt;code&gt;.cc&lt;/code&gt; files, as they happily index the functions in a file regardless of the order they appear. But there are usually a few useful tidbits of information to be found. I used &lt;a href="https://source.chromium.org/search" rel="noopener noreferrer"&gt;code search&lt;/a&gt; to find the declarations of various classes I'd read about, spending more time on those that had more to offer.&lt;/p&gt;

&lt;p&gt;In the end, I had a few questions left, and I took those to Gabriel Charette (gab@) [1]. His answers prompted some more reading and more questions (and a link to some non-public resources), but helped me make progress quickly! Asking the right person the right questions is an effective way to navigate a low-information environment, but it is difficult to do well. I'm working on it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Answers
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Why does &lt;code&gt;base::ThreadPool::PostTask&lt;/code&gt; fail?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I'll answer this at the end.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is a "Sequence" and how is it different from a "Virtual Thread"?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They are different names for the same thing. A virtual thread is conceptually a sequence of tasks executed one after the other, with the effects of one task being visible to the next. Tasks in a sequence may execute on separate threads. A &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:base/task/thread_pool/sequence.h;l=47" rel="noopener noreferrer"&gt;&lt;code&gt;Sequence&lt;/code&gt;&lt;/a&gt; implements this, by managing a TaskQueue (and a heap of delayed tasks). More on this below.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can there be multiple task queues per thread?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes. Leading to the followup question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How are tasks from multiple queues in a thread handled?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:base/task/sequence_manager/sequence_manager.h" rel="noopener noreferrer"&gt;&lt;code&gt;SequenceManager&lt;/code&gt;&lt;/a&gt; handles selecting tasks from those multiple &lt;a href="https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/task/sequence_manager/task_queue_impl.h" rel="noopener noreferrer"&gt;&lt;code&gt;TaskQueues&lt;/code&gt;&lt;/a&gt; using a &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:base/task/sequence_manager/task_queue_selector.h?q=TaskQueueSelector&amp;amp;ss=chromium%2Fchromium%2Fsrc" rel="noopener noreferrer"&gt;&lt;code&gt;TaskQueueSelector&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SequenceManager&lt;/code&gt;'s doc comment suggests that it multiplexes tasks "into a single backing sequence", but this does not appear to be the case. Instead, &lt;code&gt;ThreadController&lt;/code&gt;s call &lt;code&gt;SequenceManager::SelectNextTask&lt;/code&gt; (an override of a method from &lt;code&gt;SequencedTaskSource&lt;/code&gt;). That returns the best task to run next, and that task gets run.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a function takes a callback or delegates, what runner/queue does it use to call those?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This question was sort of off-topic. It's usually written somewhere in the docs for the class, and usually one of the "named threads" like the UI thread or IO thread.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do the &lt;code&gt;PostTask..AndReply&lt;/code&gt; methods work?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PostTask&lt;/code&gt; - just run a task (on the task runner associated with the method receiver).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PostDelayedTask&lt;/code&gt; - similar to &lt;code&gt;PostTask&lt;/code&gt;, but running the task after a delay. This adds a lot of complexity to the implementation, but is pretty simple to use.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PostTaskAndReply&lt;/code&gt; - post a task in the runner associated with the method receiver, and when that completes post a second task in the sequence that called &lt;code&gt;PostTaskAndReply&lt;/code&gt;. This provides a way to do work on a background thread and then resume the current sequence when it is done.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PostTaskAndReplyWithResult&lt;/code&gt; - like &lt;code&gt;PostTaskAndReply&lt;/code&gt; but pass return value of first task callback as an argument to the second callback. This provides an even more RPC-like call out to a background thread.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these imply some kind of &lt;code&gt;TaskRunner&lt;/code&gt; (plain, sequenced, or single-threaded). Task runners are just the gateway to send tasks into the scheduler, and the kind of task runner dictates the execution mode for the task.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If there is one SequenceManager per thread, how do thread pools work? Are there multiple SequenceManagers all competing for tasks from the same TaskQueue?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There's quite a bit of complicated work done to support both prioritizing lots of tasks in a single (named) thread and distributing work evenly in threads pools. &lt;code&gt;SequenceManager&lt;/code&gt; is only used for named threads.&lt;/p&gt;

&lt;p&gt;One of the key abstractions that bridges both named threads and thread pools is &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:base/task/thread_pool/sequence.h;bpv=1;bpt=1?q=sequence" rel="noopener noreferrer"&gt;&lt;code&gt;Sequence&lt;/code&gt;&lt;/a&gt;. This contains a queue of tasks that must be executed sequentially. &lt;/p&gt;

&lt;p&gt;In a single thread, lots of &lt;code&gt;Sequence&lt;/code&gt;s can exist at the same time, and &lt;code&gt;SequenceManager&lt;/code&gt; takes care of treating them all fairly.&lt;/p&gt;

&lt;p&gt;In a thread pool, &lt;code&gt;Sequences&lt;/code&gt; are kept in a priority queue shared among all the workers, and popped from that queue one by one. Popping sequences, rather than tasks, from the queue supports the robust guarantee that the tasks in a sequence are executed sequentially. Still, a worker thread only executes one task from a sequence, re-queuing the sequence if it's not empty.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do the "current defaults" work for SequencedTaskRunner and SingleThreadTaskRunner?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a named thread, these are fixed and are just defaults for the &lt;code&gt;SequenceManager&lt;/code&gt;. They can all be the same object, since the named thread is a single thread and thus implicitly runs things sequentially.&lt;/p&gt;

&lt;p&gt;In a pool, the entire "environment" in which a task runs is set up and torn down by &lt;a href="https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:base/task/thread_pool/task_tracker.h;bpv=1;bpt=1;l=154" rel="noopener noreferrer"&gt;&lt;code&gt;TaskTracker::RunTask&lt;/code&gt;&lt;/a&gt;, and this includes the &lt;code&gt;CurrentDefaultHandle&lt;/code&gt; for both &lt;code&gt;SequencedTaskRunner&lt;/code&gt; and &lt;code&gt;SingleThreadTaskRunner&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Which of these is set depends on the "execution mode" of the current task. So, if the current task was run via a &lt;code&gt;SequencedTaskRunner&lt;/code&gt;, then its execution mode is &lt;code&gt;kSequenced&lt;/code&gt;, and only the &lt;code&gt;SequencedTaskRunner::CurrentDefaultHandle&lt;/code&gt; will be set during execution of the task.&lt;/p&gt;

&lt;p&gt;This makes sense when you consider that a task may be invoking functions down a dependency chain. In &lt;code&gt;churl&lt;/code&gt;, we're invoking &lt;code&gt;URLRequest&lt;/code&gt; functions which call into more specific &lt;code&gt;//net&lt;/code&gt; libraries. All of those may need to schedule callbacks in the "current" sequence, and it's possible that one of the deeply buried dependencies needs to be single-threaded or (in the case that began this whole journey!) sequenced. Using the different &lt;code&gt;CurrentDefaultHandle&lt;/code&gt;s at least makes such a thing crash immediately if the requirement isn't met, rather than subtly introducing race conditions. It'd be nice if that could be caught at compile time [2]!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why does &lt;code&gt;base::ThreadPool::PostTask&lt;/code&gt; fail? &lt;em&gt;for real this time&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Briefly: my top-level &lt;code&gt;Task&lt;/code&gt; includes its dependencies, so it doesn't match the description &lt;em&gt;doesn’t have ordering or mutual exclusion requirements&lt;/em&gt; in the text quoted at the top of this post.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;base::ThreadPool::PostTask&lt;/code&gt; API is a shortcut to &lt;code&gt;base::ThreadPool::CreateTaskRunner(...)-&amp;gt;PostTask&lt;/code&gt;. Which is to say, it runs the task in the thread pool's &lt;code&gt;TaskRunner&lt;/code&gt;. A &lt;code&gt;TaskRunner&lt;/code&gt; makes no guarantees about ordering, meaning that there is no "current" &lt;code&gt;SequencedTaskRunner&lt;/code&gt; when the task is running.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;base::ThreadPool::CreateSingleThreadTaskRunner({})&lt;/code&gt; method gets a new &lt;code&gt;SingleThreadTaskRunner&lt;/code&gt; (actually, it may be a singleton, but that's not important) that knows how to schedule work into the thread pool. Posting the task on that runs the task in the thread pool, in a single-threaded context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I feel like I understand the situation quite a bit better now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I can avoid making mistakes that would lead to concurrency errors.&lt;/li&gt;
&lt;li&gt;I can understand and debug task-related errors like the one at the top of this post.&lt;/li&gt;
&lt;li&gt;I can reason about the behavior of code that uses tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's a lot more detail about jobs, efficiency (both in terms of CPU time and power consumption), responsiveness, fairness, object ownership, and so on that was interesting to learn about, but ultimately doesn't serve these goals, so I've omitted it here.&lt;/p&gt;

&lt;p&gt;I'll be making a CL to update and expand the documentation somewhat, in hopes of making this more efficient for the next person. Leaving things better than you found them is a good habit to cultivate!&lt;/p&gt;

&lt;p&gt;Next time, we'll get back to the task at hand: loading a URL. I promise.&lt;/p&gt;




&lt;p&gt;[1] All of the errors in this post are mine, not Gabriel's! All of them. All mine.&lt;/p&gt;

&lt;p&gt;[2] The distinction between "Sequenced" and "SingleThread" is basically what Rust's &lt;a href="https://doc.rust-lang.org/nomicon/send-and-sync.html" rel="noopener noreferrer"&gt;&lt;code&gt;Send&lt;/code&gt; bound&lt;/a&gt; represents. Rust's async support is conceptually similar to task scheduling, in that an executor schedules polls of various futures. Some executors poll all futures in a single thread, meaning that the futures do not need to be &lt;code&gt;Send&lt;/code&gt;. But more "advanced" executors use a pool of worker threads and work-stealing to allow futures to be polled from multiple threads (so the futures must be &lt;code&gt;Send&lt;/code&gt;), but guarantee that it won't happen simultaneously (so the futures need not be &lt;code&gt;Sync&lt;/code&gt;). I don't know of an executor that can handle both &lt;code&gt;Send&lt;/code&gt; and non-&lt;code&gt;Send&lt;/code&gt; futures.&lt;/p&gt;

</description>
      <category>chromium</category>
      <category>cpp</category>
    </item>
    <item>
      <title>Chromium Spelunking: Creating a Request</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Thu, 11 May 2023 16:52:41 +0000</pubDate>
      <link>https://dev.to/djmitche/chromium-spelunking-creating-a-request-18n1</link>
      <guid>https://dev.to/djmitche/chromium-spelunking-creating-a-request-18n1</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/djmitche/chromium-spelunking-churl-5dof"&gt;last post&lt;/a&gt;, I built an executable which created a &lt;code&gt;URLRequestContext&lt;/code&gt; and then exited. Not very exciting, but it was a bit of work! In this post, I'll be using that instance to create an actual URLRequest.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;URLRequestContext::CreateRequest&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;A skim of &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request_context.h" rel="noopener noreferrer"&gt;&lt;code&gt;url_request_context.h&lt;/code&gt;&lt;/a&gt; shows a helpful-looking function, &lt;code&gt;CreateRequest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This takes a few straightforward arguments plus a &lt;code&gt;NetworkTrafficAnnotationTag&lt;/code&gt;, and the comments focus on that type. Unfortunately, &lt;code&gt;network_traffic_annotation.h&lt;/code&gt; doesn't contain a lot of comments that might help me understand what this is and what it does. Running &lt;a href="https://github.com/djmitche/codehistory" rel="noopener noreferrer"&gt;codehistory&lt;/a&gt; on the file doesn't show much, either. From what I can guess, this is some kind of annotation that can be found in the source code and reviewed or audited. Anyway, in &lt;a href="https://chromium.googlesource.com/chromium/src/+/4cda417b6" rel="noopener noreferrer"&gt;one of the commits that modified this file&lt;/a&gt; I find &lt;code&gt;net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)&lt;/code&gt;. That didn't work immediately, but I see that the &lt;code&gt;MutableNetworkTrafficAnnotationTag&lt;/code&gt; has an explicit cast operator to &lt;code&gt;NetworkTrafficAnnotationTag&lt;/code&gt;, which does.&lt;/p&gt;

&lt;p&gt;The types work out, and the compile succeeds, but it seems I've still not squared away the task runners:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0509/212941.923727:FATAL:url_request.cc(597)] Check failed: base::SingleThreadTaskRunner::HasCurrentDefault(). 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I thought I had handled this in the last post, so this was a bit disappointing. One of things about Chromium that I'm adjusting to is that a lot of the information is stored in people, and not as data. So, I asked a few people via chat, and their responses improved my understanding of things a little. One suggestion was to look at other one-off executables like &lt;a href="https://chromium.googlesource.com/chromium/src/+/main/net/tools/net_watcher/net_watcher.cc#149" rel="noopener noreferrer"&gt;&lt;code&gt;net_watcher&lt;/code&gt;&lt;/a&gt;, or to use &lt;code&gt;base::test::TaskEnvironment&lt;/code&gt;. But I wanted to learn what was going on, rather than just getting things done. With a little more digging, I determined that &lt;code&gt;SingleThreadTaskRunner&lt;/code&gt; is a subclass of &lt;code&gt;SequentialTaskRunner&lt;/code&gt; that is capable of running tasks on the same thread, if they have some reason to be tied together like that. This is contrary to some other suggestions that &lt;code&gt;SingleThreadTaskRunner&lt;/code&gt; is only for testing!&lt;/p&gt;

&lt;p&gt;Anyway, switching&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-  auto thread_runner = base::ThreadPool::CreateSequentialTaskRunner(
&lt;/span&gt;&lt;span class="gi"&gt;+  auto thread_runner = base::ThreadPool::CreateSingleThreadTaskRunner(
&lt;/span&gt;       {base::TaskPriority::USER_VISIBLE});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;fixed this issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Up
&lt;/h2&gt;

&lt;p&gt;This was a pretty short post, mostly because I was only able to devote a few minutes at a time to this work. Next up, I will call the &lt;code&gt;Start&lt;/code&gt; method on the &lt;code&gt;URLRequest&lt;/code&gt;, which will require a &lt;code&gt;URLRequest::Delegate&lt;/code&gt;. Once the header is read, I'll call &lt;code&gt;Read&lt;/code&gt; to read the response body. The end is in sight!&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>chromium</category>
    </item>
    <item>
      <title>Chromium Spelunking: Churl</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Mon, 08 May 2023 18:47:41 +0000</pubDate>
      <link>https://dev.to/djmitche/chromium-spelunking-churl-5dof</link>
      <guid>https://dev.to/djmitche/chromium-spelunking-churl-5dof</guid>
      <description>&lt;p&gt;At the end of my &lt;a href="https://dev.to/djmitche/chromium-spelunking-life-and-times-536b"&gt;last post&lt;/a&gt; I indicated I would try to build a simple executable to fetch a URL, similar to curl. &lt;code&gt;churl&lt;/code&gt; sounds like a suitably silly name for it.&lt;/p&gt;

&lt;p&gt;This post is going to be a little on the long side -- it's leaning into the "lightly edited lab notebook" format, in hopes of highlighting some of the places I got stuck.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Executable
&lt;/h2&gt;

&lt;p&gt;I want to focus on my goals here -- understanding the network stack, specifically proxies and QUIC -- so I don't want to get distracted with things like how to set up Ninja to create a new executable. So, I went looking for something that was near to what I wanted and which I could copy/paste and modify. I got lucky! There is a &lt;a href="https://www.chromium.org/quic/playing-with-quic/" rel="noopener noreferrer"&gt;&lt;code&gt;quic_client&lt;/code&gt;&lt;/a&gt; executable that seems &lt;em&gt;quite&lt;/em&gt; close, really. However, it's specific to QUIC and I want to make something that begins at &lt;code&gt;URLRequest&lt;/code&gt;. Still, this gives me an easy way to create a new executable in &lt;code&gt;net/BUILD.gn&lt;/code&gt; and do a simple "Hello World":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Hello, world."&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                                                                                                                                                                                  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting to URLRequestContext
&lt;/h2&gt;

&lt;p&gt;From the previous post, step one is going to be getting a &lt;code&gt;URLRequestContext&lt;/code&gt; up and running, and that requires &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request_context_builder.h" rel="noopener noreferrer"&gt;a builder&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ThreadPoolInstance
&lt;/h3&gt;

&lt;p&gt;Naively trying to create such a thing gets me an error because I haven't initialized a thread pool. The network stack does seem to use a lot of the task-posting magic, so I suppose that's necessary! A bit of guessing based on &lt;code&gt;base/test/task_environment.cc&lt;/code&gt; leads me to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPoolInstance&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPoolImpl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my histogram"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and on to the next error. I am hoping to only have to make two or three of these "wild guesses" before things start working. Beyond that point, when something doesn't work it will be almost impossible for me to figure out which of the &lt;em&gt;n&amp;gt;3&lt;/em&gt; things I do not understand might be malfunctioning.&lt;/p&gt;

&lt;h3&gt;
  
  
  SequencedTaskRunner
&lt;/h3&gt;

&lt;p&gt;Next up, I need a &lt;code&gt;SequencedTaskRunner&lt;/code&gt; to run tasks on that thread pool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0508/164407.189292:FATAL:post_task_and_reply_impl.cc(158)] Check failed: has_sequenced_context || !post_task_success. 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checking &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:base/task/sequenced_task_runner.h?q=SequencedTaskRunner" rel="noopener noreferrer"&gt;&lt;code&gt;sequenced_task_runner.h&lt;/code&gt;&lt;/a&gt; shows a lot of docs &lt;em&gt;about&lt;/em&gt; the type, but not how to construct it. The bottom of the doc comments mentions some "theoretical implementations", suggesting that this is an abstract base class, and in fact a few methods are &lt;code&gt;= 0&lt;/code&gt;. So, where are the implementations? Ordinarily I'd use CodeSearch for this, but it seems that the 91 subclasses are more than its little brain can handle.&lt;/p&gt;

&lt;p&gt;I continued on a little down this path, but I am learning that when I find myself reading the Chromium source, I'm looking in the wrong place. In fact, the nice &lt;a href="https://chromium.googlesource.com/chromium/src/+/HEAD/docs/threading_and_tasks.md" rel="noopener noreferrer"&gt;Threading and Tasks&lt;/a&gt; document includes snippets that create task runners:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;thread_runner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPool&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CreateTaskRunner&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TaskPriority&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;USER_VISIBLE&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same error occurs, I think because while this creates a new task runner, it does not set it as the default. It looks like &lt;code&gt;CreateDefaultHandle&lt;/code&gt; is an RAII wrapper for setting a task runner as the default, so let's try&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SequencedTaskRunner&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CurrentDefaultHandle&lt;/span&gt; &lt;span class="nf"&gt;active_thread_pool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread_runner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This call itself fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0508/171849.025900:FATAL:sequenced_task_runner.cc(99)] Check failed: task_runner_-&amp;gt;RunsTasksInCurrentSequence(). 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The comment docs for &lt;code&gt;RunsTasksInCurrentSequence&lt;/code&gt; suggest that it is meant to be called within a task, so maybe I need to run the remainder of &lt;code&gt;churl&lt;/code&gt; in a task in this runner?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;URLRequestContextBuilder&lt;/span&gt; &lt;span class="n"&gt;url_request_context_builder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;url_request_context_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_user_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dustin's Experiment"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;url_request_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url_request_context_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="n"&gt;DLOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Hello, world."&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;url_request_context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPoolInstance&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPoolImpl&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my histogram"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;thread_runner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPool&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CreateSequencedTaskRunner&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;TaskPriority&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;USER_VISIBLE&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="n"&gt;thread_runner&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;PostTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FROM_HERE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BindOnce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indeed, that compiles, but since &lt;code&gt;main&lt;/code&gt; exits immediately after posting the task, it doesn't print "Hello, world."&lt;/p&gt;

&lt;p&gt;Referring to the &lt;em&gt;Threading and Tasks&lt;/em&gt; document again, I tried &lt;code&gt;base::RunLoop().RunUntilIdle()&lt;/code&gt;, but this seems to require that it be called with the current loop set, and that seems a bit circular. Lower down I see &lt;code&gt;base::RunLoop::Run&lt;/code&gt;, which will call until a &lt;code&gt;QuitClosure&lt;/code&gt; is run. That sounds better, but ultimately has the same issue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0508/173608.004631:FATAL:single_thread_task_runner.cc(44)] Check failed: handle. Error: This caller requires a single-threaded context (i.e. the current task needs to run from a SingleThreadTaskRunner). If you're in a test refer to //docs/threading_and_tasks_testing.md.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Further down the document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// To block until all tasks posted to thread pool are done running:&lt;/span&gt;
&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPoolInstance&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;FlushForTesting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But that just hangs without actually running the task. Even &lt;em&gt;further&lt;/em&gt; down the document, there's a section entitled "Using ThreadPool in a New Process", and it turns out that this is what I'm trying to do. It uses&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ThreadPoolInstance&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CreateAndStartWithDefaultParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"process_name"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of the initialization I was using. I don't really understand the difference, but this appears to make things work and gets the next error from &lt;code&gt;net::URLRequestContextBuilder::Build&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0508/174429.973862:FATAL:configured_proxy_resolution_service.cc(800)] Check failed: proxy_config_service. 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Proxy Config Service / Proxy Resolution Service
&lt;/h3&gt;

&lt;p&gt;Proxies! At least that's relevant to my interests.&lt;/p&gt;

&lt;p&gt;Following the traceback for that failure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#6 0x7f00db30f76f logging::CheckError::~CheckError()
#7 0x7f00dd28f8f7 net::ConfiguredProxyResolutionService::CreateUsingSystemProxyResolver()
#8 0x7f00dd63b1b7 net::URLRequestContextBuilder::CreateProxyResolutionService()
#9 0x7f00dd637485 net::URLRequestContextBuilder::Build()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it looks like &lt;code&gt;Build&lt;/code&gt; is passing a NULL unique_ptr for &lt;code&gt;proxy_config_service&lt;/code&gt; to &lt;code&gt;CreateProxyResolutionService&lt;/code&gt;, and adding some debug prints confirms that. In fact, the debug prints confirm that &lt;code&gt;BUILDFLAG(IS_LINUX)&lt;/code&gt; is not true, despite building this on a Linux system. I don't know a quick way to fix that, so hopefully I can work around it.&lt;/p&gt;

&lt;p&gt;Commenting out the build conditionals in &lt;a href="https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request_context_builder.cc;l=445?q=net%2Furl_request%2Furl_request_context_builder.cc" rel="noopener noreferrer"&gt;&lt;code&gt;url_request_context_builder.cc&lt;/code&gt;&lt;/a&gt; gets a different error, I think to do with &lt;code&gt;ProxyConfigService::CreateSystemProxyConfigService&lt;/code&gt; requiring a &lt;code&gt;SingleThreadTaskRunner&lt;/code&gt; when we're using a &lt;code&gt;SequencedTaskRunner&lt;/code&gt;, so maybe that's a dead-end.&lt;/p&gt;

&lt;p&gt;Maybe I can provide a stubbed-out implementation of these types? It looks like &lt;code&gt;ProxyConfigService&lt;/code&gt; can create a &lt;code&gt;ProxyResolutionService&lt;/code&gt;, or I can just specify a &lt;code&gt;ProxyResolutionService&lt;/code&gt; directly. Looking for subclasses of both abstract base classes, I found a local &lt;a href="https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:net/proxy_resolution/proxy_config_service.cc;l=79;drc=e0e0d24aaa54727dc0a8bc4b159ccdf80d3f5d8d;bpv=1;bpt=1" rel="noopener noreferrer"&gt;&lt;code&gt;ProxyConfigServiceDirect&lt;/code&gt;&lt;/a&gt; which just always returns DIRECT. That looks useful, so I'll copy-paste it (and add the necessary namespaces):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Config getter that always returns direct settings.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProxyConfigServiceDirect&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ProxyConfigService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nl"&gt;public:&lt;/span&gt;
  &lt;span class="c1"&gt;// ProxyConfigService implementation:&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;AddObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Observer&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;RemoveObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Observer&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ProxyConfigService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ConfigAvailability&lt;/span&gt; &lt;span class="n"&gt;GetLatestProxyConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ProxyConfigWithAnnotation&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ProxyConfigWithAnnotation&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;CreateDirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CONFIG_VALID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;URLRequestContextBuilder&lt;/span&gt; &lt;span class="n"&gt;url_request_context_builder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;url_request_context_builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_proxy_config_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_unique&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProxyConfigServiceDirect&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="c1"&gt;// ..&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and with that, I've successfully built a &lt;code&gt;UrlRequestContext&lt;/code&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking In
&lt;/h2&gt;

&lt;p&gt;OK, so I've made some progress today. A lot of this has been trial-and-error. There are two problems with this approach. First, it means I don't really learn how things work -- for example, I don't know why so many options for setting up a task runner failed. But I can add an item to my task list to learn more about that some day, and carry on with my current project.&lt;/p&gt;

&lt;p&gt;Second, the distinction between "OK" and "Error" in this kind of trial-and-error is not always clear. In this case, I thought I had finished the creation of the thread pool successfully, but it turned out I had to revisit this and do it a different way. That was down to luck, and with a few more repetitions of trial-and-error, the universe of unknown things that could be wrong is so large that no amount of luck is enough to make progress.&lt;/p&gt;

&lt;p&gt;The tools also let me down a bit here: CodeSearch was overwhelmed and unable to give me answers. I omitted it above, but I fell back to &lt;code&gt;git grep&lt;/code&gt;. Like a pocket-knife, it's a tool that isn't fancy but is always there and always works. Another go-to tool that I used here was debug prints (in this case, &lt;code&gt;DLOG(ERROR) &amp;lt;&amp;lt; "HERE 1";&lt;/code&gt; and incrementing the number). It's not especially cool, but it provides reliable, ground-truth information.&lt;/p&gt;

&lt;p&gt;The code itself let me down a little, too. Classes in &lt;code&gt;base&lt;/code&gt; seem to be well-commented, but with deep technical detail and not answers to questions like "how do you create an instance". Maybe that's OK -- it's a lot to ask from code comments -- but it's a reminder to me that I need to look outside of the code for higher-level documentation.&lt;/p&gt;

</description>
      <category>chromium</category>
      <category>cpp</category>
    </item>
    <item>
      <title>Chromium Spelunking: Life and Times</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Fri, 05 May 2023 16:21:30 +0000</pubDate>
      <link>https://dev.to/djmitche/chromium-spelunking-life-and-times-536b</link>
      <guid>https://dev.to/djmitche/chromium-spelunking-life-and-times-536b</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/djmitche/chromium-spelunking-getting-started-n84"&gt;last post&lt;/a&gt;, I read through one of the guides to the network stack and summarized my findings, with two more to go.  In this post, I'll cover those two subsequent documents, and then plot how I'll start digging in deeper.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/life-of-a-url-request.md" rel="noopener noreferrer"&gt;Life of a URLRequest&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This document is a top-down summary of how URLs are fetched, meaning it begins with some function that says "here's a URL, go get it" and probably ends with some details of TCP connections and HTTP transactions. I tend to think in the opposite order: bottom-up. So, I want to understand how TCP connections are handled and what the API is for that implementation. Once I've got that down, I want to know how the next higher layer (HTTP?) operates and what its API is. And so on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preliminaries
&lt;/h3&gt;

&lt;p&gt;This document begins with some general observations, which may help when it comes time to unravel how to find instances of the dozens of classes involved here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;URLRequestContext&lt;/code&gt; is the top-level entry point for loading a URL, and creates &lt;code&gt;URLRequest&lt;/code&gt; instances. It seems like it encapsulates the "top half" of the network stack, down to where actual network connections occur.&lt;/li&gt;
&lt;li&gt;That second level is encapsulated in &lt;code&gt;HttpNetworkSession&lt;/code&gt;, which handles network streams, socket pools, and so on.&lt;/li&gt;
&lt;li&gt;Following a pattern that is common to Chromium, sets of callbacks for users of the network stack are bundled together in "Delegate" classes, in this case &lt;code&gt;URLRequest::Delegate&lt;/code&gt; (specific to a request) and &lt;code&gt;NetworkDelegate (global to the&lt;/code&gt;URLRequestContext`).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are some details about how other parts of Chromium communicate with the network stack via Mojo, but for the moment my focus is within that boundary, so I'll ignore that. In fact, that makes quite a bit of this document irrelevant to our purposes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip to Toe and Back
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;network::URLLoader&lt;/code&gt; (part of the network Mojo service, by the &lt;code&gt;network::&lt;/code&gt; namespace) creates a &lt;code&gt;URLRequest&lt;/code&gt;. This is handed to &lt;code&gt;network::ResourceScheduler&lt;/code&gt; to actually start the request. This suggests that a URLRequest doesn't start immediately on creation -- something to look out for later.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;URLRequest&lt;/code&gt; gets an implementation of &lt;code&gt;URLRequestJob&lt;/code&gt; from the &lt;code&gt;URLRequestJobFactory&lt;/code&gt;. Specifically, that will be a &lt;code&gt;URLRequestHttpJob&lt;/code&gt; instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;URLRequestHttpJob&lt;/code&gt; attaches cookies to the request (and probably some other stuff!) and then makes an &lt;code&gt;HttpCache::Transaction&lt;/code&gt; and activates it. It seems the HTTP cache is a read-through cache, as on a miss the cache is responsible for the next steps:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the &lt;code&gt;HttpNetworkLayer&lt;/code&gt; to create a new &lt;code&gt;HttpNetworkTransaction&lt;/code&gt;. The document says it "transparently wraps" this object, but it's unclear what that might mean.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;HttpNetworkTransaction&lt;/code&gt; then gets an &lt;code&gt;HttpStream&lt;/code&gt; from the &lt;code&gt;HttpStreamFactory&lt;/code&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I imagine that by the time we have an &lt;code&gt;HttpStream&lt;/code&gt;, we're in the lower of the two "big layers", but I don't see any mention of &lt;code&gt;HttpNetworkSession&lt;/code&gt; here. Presumably &lt;code&gt;HttpStream&lt;/code&gt; is an abstraction for a connection that can carry requests and responses, but doesn't get into the specifics of HTTP versions or connection mechanisms. Continuing with the process of creating an HttpStream (assuming the simple case with no pre-existing sockets):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HttpStreamFactory::Job&lt;/code&gt; needs to get a client socket (which it will store in a &lt;code&gt;ClientSocketHandle&lt;/code&gt;) from the &lt;code&gt;ClientSocketPoolManager&lt;/code&gt;. It sounds like this object is where proxies might get hooked in, probably with some recursive calls, but in this simple case it relies on the &lt;code&gt;TransportClientSocketPool&lt;/code&gt;. I suppose "Transport" here means over an actual HTTP/x protocol on a network connection (so, not proxied). There's a &lt;code&gt;ClientSocketPoolBase&lt;/code&gt; and &lt;code&gt;ClientSocketPoolBaseHelper&lt;/code&gt; involved here, too - are you getting some strong Java vibes here?&lt;/p&gt;

&lt;p&gt;In this case the pool is empty, so it needs to create a new connection, via a &lt;code&gt;TransportConnectJob&lt;/code&gt; (there's that word "job" again..). This will handle DNS resolution, which is probably fascinating with the advent of DoH but out of scope for me at the moment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;HttpStreamFactory::Job&lt;/code&gt; gets the connection object (wrapped in a &lt;code&gt;ClientSocketHandle&lt;/code&gt;) and creates an &lt;code&gt;HttpBasicStream&lt;/code&gt;. I'm guessing this is a subclass of &lt;code&gt;HttpStream&lt;/code&gt;, as it passes this back to the &lt;code&gt;HttpNetworkTransaction&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;HttpNetworkTransaction&lt;/code&gt; then passes the request header and body to &lt;code&gt;HttpBasicStream&lt;/code&gt;, which uses an &lt;code&gt;HttpStreamParser&lt;/code&gt; to write the headers and body to the stream. That's an interesting use of a "parser", but OK.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;code&gt;HttpStreamParser&lt;/code&gt; then waits for the response header, parses it, and sends it back up the stack: &lt;code&gt;HttpNetworkTransaction&lt;/code&gt;, &lt;code&gt;HttpCache::Transaction&lt;/code&gt; (which probably caches a copy, if possible), and &lt;code&gt;URLRequestHttpJob&lt;/code&gt; (which saves cookies), and &lt;code&gt;URLRequest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This section mentions HTTP/1.x, so it's possible that H2 and QUIC diverge from this process somewhere before this point.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The body is read by passing buffers all the way up and down the stack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once the request is complete, &lt;code&gt;HttpNetworkTransaction&lt;/code&gt; determines whether the connection is reusable -- depending on headers in the connection, the response, and so on -- and either returns it to the pool or destroys it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of that seems comprehensible enough to provide a scaffolding for understanding this later. I've noted a few questions that I'd like to answer, too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What is a "job"? This seems like a pattern like factories and builders, but maybe more specific to the network stack or chromium (like delegates).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Where do H2 and QUIC diverge in this process?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What do things look like, at this level of detail, when there's a proxy involved?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Where does TLS fit in?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happily, most of these are covered in the remainder of the document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ownership (??!)
&lt;/h2&gt;

&lt;p&gt;The next bit of the document contains a comically complex ownership diagram that seems to combine ownership, inheritance, templating, and interfaces. It has footnotes for additional information that does not appear "clearly" in the diagram! Perhaps this will be a useful reference for me later as I try to avoid introducing use-after-free or double-free bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Socket Pools
&lt;/h2&gt;

&lt;p&gt;Socket pools are keyed by a "group name", such that connections with the same group name can be used interchangeably. This is made up of a host, port, protocol, and "privacy mode".&lt;/p&gt;

&lt;p&gt;Sockets aren't OS-level sockets, and it seems there are a number of implementations of sockets, all with their own pools. In fact, these can be layered, so a higher-level socket utilizes a lower-level socket. I suppose the obvious case here is a TLS socket utilizing a TCP socket. &lt;code&gt;ConnectJob&lt;/code&gt; is another "job" implementation here, in this case performing the operations to initiate a socket connection.&lt;/p&gt;

&lt;p&gt;There are some details here of the class relationships that I will want to refer back to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proxies
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;HttpStreamFactory::Job&lt;/code&gt; uses a "Proxy Service" to determine which proxies to use for a request. Each proxy then exposes a socket pool for connections via that socket, and &lt;code&gt;HttpStreamFactory&lt;/code&gt; gets a socket from that pool.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP/2
&lt;/h2&gt;

&lt;p&gt;HTTP/2 (a.k.a. SPDY) has a slightly different "shape" from HTTP/1.x. It works over a TCP connection just like HTTP/1.x, and can be activated during TLS negotiation. It allows multiple, concurrent connections in a single session (= TCP connection). The network stack will multiplex multiple concurrent requests over a single session, but it appears that's not done via another layer of connection pooling. Rather, the &lt;code&gt;HttpStreamFactory::Job&lt;/code&gt; creates a &lt;code&gt;SpdySession&lt;/code&gt; and from that a &lt;code&gt;SpdyHttpStream&lt;/code&gt;, which it passes to the &lt;code&gt;HttpNetworkTransaction&lt;/code&gt;. But it's not clear from the text how an existing &lt;code&gt;SpdySession&lt;/code&gt; would be used to create a new &lt;code&gt;SpdyHttpStream&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There's some extra optimization here to avoid making multiple TCP connections to a server that supports HTTP/2.&lt;/p&gt;

&lt;h2&gt;
  
  
  QUIC
&lt;/h2&gt;

&lt;p&gt;QUIC (the transport beneath HTTP/3) has a &lt;em&gt;very&lt;/em&gt; different shape from HTTP/1.x. To begin with, it operates over UDP, not TCP. A server's support for QUIC is advertised in headers, so the browser must "remember" which servers support QUIC and try to connect with QUIC when that server is next used.&lt;/p&gt;

&lt;p&gt;When a server supports QUIC, &lt;code&gt;HttpStreamFactory&lt;/code&gt; will "race" two jobs - one for QUIC and one for all previous protocols -- and pick the one that gets a stream first. This strategy is reminiscent of the &lt;a href="https://en.wikipedia.org/wiki/Happy_Eyeballs" rel="noopener noreferrer"&gt;"happy eyeballs"&lt;/a&gt; algorithm for IPv4 and IPv6. It gets the best performance for the user at the cost of "wasting" some connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md" rel="noopener noreferrer"&gt;Proxy support in Chrome&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I set out to read this document in the previous post, but on closer inspection it's not especially relevant. It mostly covers how proxies are configured, and mostly from the perspective of someone doing the configuring.&lt;/p&gt;

&lt;p&gt;It does link to &lt;a href="https://bugs.chromium.org/p/chromium/issues/detail?id=969859" rel="noopener noreferrer"&gt;crbug 969859&lt;/a&gt; where support for QUIC proxies was disabled by default. As with many Chromium bugs, it and the blocked/blocking bugs are pretty low on details!&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;That exhausts the "obvious" sources of documentation, although I'm sure I'll find some more as I proceed. Chromium development has a common practice of putting documentation in Google Docs documents. These are &lt;em&gt;usually&lt;/em&gt; (but not always) linked from somewhere (a CL, a bug, or maybe in the source), and they are &lt;em&gt;sometimes&lt;/em&gt; publicly readable (I won't be able to comment on anything that is not). These documents are generally "design documents", so they discuss a proposed change along with alternatives and potential impacts. What they do not do is document how things work -- they generally only make sense if you understand the state of the codebase &lt;em&gt;before&lt;/em&gt; the proposed change, and if no &lt;em&gt;subsequent&lt;/em&gt; change has been made to the same code.&lt;/p&gt;

&lt;p&gt;I hope it's clear why this situation is a nightmare from an approachability perspective!&lt;/p&gt;

&lt;p&gt;I have two next steps in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Begin exploring the code from the bottom up (so, beginning with some of the simpler socket pool implementations). I have written a &lt;a href="https://github.com/djmitche/codehistory" rel="noopener noreferrer"&gt;useful script&lt;/a&gt; to help me dig up the "hidden documentation" for a piece of code, so I'll be interested to see how that works in practice.&lt;/li&gt;
&lt;li&gt;Try to write a &lt;code&gt;curl&lt;/code&gt;-like utility that embeds the network stack and fetches the URL given on the command line. I expect this will be a &lt;em&gt;substantial&lt;/em&gt; amount of work -- I think it involves building a new "embedder" and likely implementing lots of complex delegate methods -- but I might learn something from the attempt even if I don't finish it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So far I've just been passively "absorbing" information, and that's typically not a great way to learn, so I am inclined to get a start start on the &lt;code&gt;curl&lt;/code&gt;-like utility just to get my fingers on the keyboard for a bit.&lt;/p&gt;

</description>
      <category>chromium</category>
      <category>cpp</category>
    </item>
    <item>
      <title>Chromium Spelunking: Getting Started</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Mon, 24 Apr 2023 21:23:29 +0000</pubDate>
      <link>https://dev.to/djmitche/chromium-spelunking-getting-started-n84</link>
      <guid>https://dev.to/djmitche/chromium-spelunking-getting-started-n84</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I'm now working day-to-day on Chromium, the open-source code-base behind Chrome. It's a C++ codebase with a healthy dose of Java and JS thrown in, although I'm mostly in the C++ bits of the codebase. It's been a steep learning curve, and I'd like to start documenting that learning curve with a few goals in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structure my own thinking and learning about Chromium.&lt;/li&gt;
&lt;li&gt;Help others who are beginning to work on Chromium.&lt;/li&gt;
&lt;li&gt;Start to identify some ways that Chromium could improve its &lt;em&gt;approachability&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That term will become a theme. An &lt;em&gt;approachable&lt;/em&gt; codebase is one where it is easy for a newcomer to get started. I think this is an important aspect of any codebase, but especially open source codebases. Developers move from project to project all the time, as I just did. An approachable codebase lets a developer get going quickly. It benefits existing developers, too: if new developers can find answers to questions, then more experienced developers don't have to spend time answering those questions. &lt;/p&gt;

&lt;p&gt;In the last few weeks, several of my questions have garnered answers of the form "I don't work on Chromium anymore, but ..." While I feel for these experienced engineers haunted by the ghosts of projects past, if the codebase was more approachable then I wouldn't have to ask them!&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Expect
&lt;/h2&gt;

&lt;p&gt;I'll be blogging about my spelunking as it happens. Think of this as a lightly-edited lab notebook: all of the false starts, incorrect assumptions, and missed connections are here for you to see. I'll try to use complete sentences, explain things clearly, and organize my thoughts into a coherent order within each post.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Task
&lt;/h2&gt;

&lt;p&gt;The project I'm gearing up for involves adding some additional functionality to Chromium's network stack, to allow it to proxy QUIC connections over other QUIC connections. It's OK if you don't know what that means just yet -- I only have the vaguest sense myself. For the moment, I need to know how the network implementation is put together, so that I can see what parts I will need to modify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Big Picture
&lt;/h2&gt;

&lt;p&gt;My first step is to get the "big picture": the major components and patterns. With this information, I can start looking at the details, confident that I understand where those details fit. This is a "top-down" approach. And I typically begin by looking for developer documentation. In the case of the Chromium network layer, I found the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/code-patterns.md" rel="noopener noreferrer"&gt;Chrome Network Stack Common Coding Patterns&lt;/a&gt; - an overview of how the code in &lt;code&gt;//net&lt;/code&gt; is built. This will help me understand code as I begin reading it.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/life-of-a-url-request.md" rel="noopener noreferrer"&gt;Life of a URLRequest&lt;/a&gt; - a step-by-step tour of the network stack's main job: fetching a URL. This document names a lot of classes and methods that will be useful later.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md" rel="noopener noreferrer"&gt;Proxy Support in Chrome&lt;/a&gt; - more detail on the network stack's proxy support.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few general lessons from the coding patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lots of functions in the stack's API use variants of the libc return value style: negative numbers are error codes, positive numbers indicate success, perhaps as a byte count, and zero can indicate simple success or EOF, depending on context.&lt;/li&gt;
&lt;li&gt;Some functions can either finish synchronously or asynchronously. As a baseline, a C syscall like write(2) will return EAGAIN when it would otherwise block, and the expectation is that it will be called again when the application believes the write might succeed. This would continue until the call is successful. The Chromium functions all take a callback, and it's unclear from this description whether a synchronous completion invokes this callback, or expects the caller to do so. So, I'll need to figure that out, and document it.&lt;/li&gt;
&lt;li&gt;It's common for network types to be structured as state machines, with a &lt;code&gt;DoLoop&lt;/code&gt; at the core calling &lt;code&gt;DoXxx&lt;/code&gt; methods based on a &lt;code&gt;next_state_&lt;/code&gt; instance variable until either it must wait for something to complete (&lt;code&gt;ERR_IO_PENDING&lt;/code&gt;) or the request is complete. There's a bit more data about what is responsible for calling the callback which I'll need to explore as I start reading the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "Life of a URLRequest" document is long and detailed, so I'll save that and the proxy document for the next post.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>chromium</category>
    </item>
    <item>
      <title>Language Design Lessons: Automatic Interfaces</title>
      <dc:creator>djmitche</dc:creator>
      <pubDate>Mon, 24 Apr 2023 19:30:04 +0000</pubDate>
      <link>https://dev.to/djmitche/automatic-interfaces-35hg</link>
      <guid>https://dev.to/djmitche/automatic-interfaces-35hg</guid>
      <description>&lt;p&gt;After diving a little too heavily into object-orientation, language design has shifted to interfaces as a way to support dynamic dispatch without tying types into a single inheritance tree.&lt;/p&gt;

&lt;p&gt;A common example is a "reader" interface.  Functionality which needs to read data (such as a decompression library) only requires that its input implement the reader interface.  Multiple types can implement this interface -- files on disk, network sockets, in-memory buffers, and so on.&lt;/p&gt;

&lt;p&gt;Lots of simple interfaces work this way: their behavior is defined by one method, and often the interface is named after this method, with an "er" suffix: "Reader", "Listener", "Watcher", etc.&lt;/p&gt;

&lt;p&gt;In most languages, a type must declare that it implements an interface.  In Rust, this might look like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;Default&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;MyType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;foos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;Default&lt;/code&gt; is the interface being implemented (Rust uses the term "trait" instead of "interface", with a slightly different meaning).&lt;/p&gt;

&lt;p&gt;Go takes a different approach: an interface defines a set of method signatures, and &lt;em&gt;any&lt;/em&gt; type with matching methods implicitly implements the interface.  For example, the io.Writer interface is defined as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Writer&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any type can implement Writer just by implementing a matching Write method.&lt;/p&gt;

&lt;p&gt;In an ecosystem of code written by different people, this has the advantage that a type you don't control can implement an interface you do control.  This can be especially useful for mocking third-party types when testing.&lt;/p&gt;

&lt;p&gt;However, this design choice assumes that the nature of an interface is entirely defined by its method signatures. For example, a module framework might define a "module" interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Module&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Start starts the module's execution, and returns&lt;/span&gt;
    &lt;span class="c"&gt;// immediately.&lt;/span&gt;
    &lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Stop signals the module to stop, blocking until it&lt;/span&gt;
    &lt;span class="c"&gt;// does so.&lt;/span&gt;
    &lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; 

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;AddModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the comments capture some information about the interface that is not represented in the method declarations, and thus not checked by the compiler.&lt;/p&gt;

&lt;p&gt;In fact, lots of types have &lt;code&gt;Start&lt;/code&gt; and &lt;code&gt;Stop&lt;/code&gt; methods matching this interface. Are these modules? The compiler thinks so! Perhaps types from a package of service utilities have these methods, but with an additional &lt;code&gt;Wait&lt;/code&gt; method that waits for the module to actually stop. Mixing such utilities would silently terminate those modules uncleanly.&lt;/p&gt;

&lt;p&gt;If you're familiar with duck-typed languages like Python or JS, this probably isn't surprising: it's up to you as the human at the keyboard to ensure that your types have the necessary behaviors, or things will fail at runtime.&lt;/p&gt;

&lt;p&gt;But Go is strongly typed, and one of strong typing's benefits is surfacing errors like this at compile time. In fact, it's quite common to use &lt;code&gt;interface {}&lt;/code&gt; in Go code, and &lt;em&gt;everything&lt;/em&gt; satisfies this interface -- hardly strong typing!&lt;/p&gt;

&lt;p&gt;The introduction of generics in 2022 has helped this situation before. Before generics, a general-purpose LRU library might have used &lt;code&gt;interface{}&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lru&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Lru&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here callers would apply a type assertion to downcast that &lt;code&gt;interface{}&lt;/code&gt; to the expected type. But nothing prevents objects of different types being stored in the same cache, so the type must be checked for every object - a real runtime cost for a performance-sensitive library. With generics, that can be written as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lru&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Lru&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;..&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;ensuring, at compile time, that only T's are stored in the cache.&lt;/p&gt;

&lt;p&gt;This may be a case where allowing &lt;em&gt;too much&lt;/em&gt; flexibility in a language allows undetected bugs and prevents useful optimizations. Conversely, a carefully constrained language can eliminate entire classes of incorrect code, while also allowing optimizations based on broad, language-enforced invariants.&lt;/p&gt;

&lt;p&gt;[cover photo: &lt;a href="https://www.flickr.com/photos/chrisdag/5488664355/" rel="noopener noreferrer"&gt;@chrisdag&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;P.S. This will be the last installment in this very short series. I've moved on from the work that had me writing Go every day. Look forward to posts from a Chromium developer!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
