1 00:00:00,480 --> 00:00:03,480 foreign 2 00:00:08,280 --> 00:00:13,799 flag that we have at Curtis Maloney and 3 00:00:11,160 --> 00:00:16,500 then Evan Brumley straight after this 4 00:00:13,799 --> 00:00:19,680 one too and then we break an early break 5 00:00:16,500 --> 00:00:22,500 for lunch for us 6 00:00:19,680 --> 00:00:28,010 all right so we have Curtis Maloney with 7 00:00:22,500 --> 00:00:31,800 HTTP request an unsung hero of Django 8 00:00:28,010 --> 00:00:35,100 [Applause] 9 00:00:31,800 --> 00:00:37,320 yay it's showing up okay hi everyone 10 00:00:35,100 --> 00:00:39,239 um I was goaded into this talk by 11 00:00:37,320 --> 00:00:40,700 somebody on Twitter I will just say that 12 00:00:39,239 --> 00:00:43,559 up front 13 00:00:40,700 --> 00:00:45,180 I'm funky Bob on IRC where I've been 14 00:00:43,559 --> 00:00:47,520 helping people over the last 20 years 15 00:00:45,180 --> 00:00:49,980 with their various coding problems 16 00:00:47,520 --> 00:00:53,280 um I've been using python since the late 17 00:00:49,980 --> 00:00:55,100 90s started on version 1.4 18 00:00:53,280 --> 00:00:59,039 Believe it or else 19 00:00:55,100 --> 00:01:01,680 16 years in the Django Community I was 20 00:00:59,039 --> 00:01:04,080 invited to join the Django core team in 21 00:01:01,680 --> 00:01:05,519 2014 there is no core team anymore but 22 00:01:04,080 --> 00:01:08,340 that's another story I'd like to thank 23 00:01:05,519 --> 00:01:10,979 my employer Burns Red 24 00:01:08,340 --> 00:01:13,560 for uh helping me be here today 25 00:01:10,979 --> 00:01:17,220 all right now 26 00:01:13,560 --> 00:01:19,260 through my time with using Django 27 00:01:17,220 --> 00:01:21,240 early on I had realized that the 28 00:01:19,260 --> 00:01:23,220 framework needed to do two things there 29 00:01:21,240 --> 00:01:24,600 were two aspirations that any framework 30 00:01:23,220 --> 00:01:26,280 should really be 31 00:01:24,600 --> 00:01:28,920 aiming for 32 00:01:26,280 --> 00:01:31,320 in making our lives better the first is 33 00:01:28,920 --> 00:01:34,500 to protect her office from the tedious 34 00:01:31,320 --> 00:01:36,180 things so in Django we have the orm so 35 00:01:34,500 --> 00:01:38,460 that we don't have to deal with raw SQL 36 00:01:36,180 --> 00:01:40,439 we have templates so we don't have to 37 00:01:38,460 --> 00:01:41,880 deal with it a lot of stuff is there so 38 00:01:40,439 --> 00:01:43,680 you don't have to do that thing you do 39 00:01:41,880 --> 00:01:45,960 all the time and it doesn't have to 40 00:01:43,680 --> 00:01:48,000 consume all of your work the other thing 41 00:01:45,960 --> 00:01:50,340 is to protect developers from the 42 00:01:48,000 --> 00:01:52,439 dangerous things these are the mistakes 43 00:01:50,340 --> 00:01:56,220 we often make the little corner cases we 44 00:01:52,439 --> 00:01:59,700 often forget or the security of mistakes 45 00:01:56,220 --> 00:02:02,579 the crop up all too often 46 00:01:59,700 --> 00:02:04,259 the goal of this talk is pretty simple 47 00:02:02,579 --> 00:02:05,820 it is not 48 00:02:04,259 --> 00:02:07,740 to have everyone familiar with 49 00:02:05,820 --> 00:02:09,239 absolutely every aspect of what's in the 50 00:02:07,740 --> 00:02:11,640 request object 51 00:02:09,239 --> 00:02:14,040 the goal of this talk is to show you 52 00:02:11,640 --> 00:02:16,500 just how much tedium and danger and how 53 00:02:14,040 --> 00:02:18,300 many sharp edges that Django is 54 00:02:16,500 --> 00:02:21,060 protecting you from just as this one 55 00:02:18,300 --> 00:02:23,480 object and you may not even realize it a 56 00:02:21,060 --> 00:02:23,480 lot of the time 57 00:02:23,580 --> 00:02:28,020 a lot of this comes down to the dry 58 00:02:25,800 --> 00:02:30,360 concept the don't repeat yourself which 59 00:02:28,020 --> 00:02:33,660 I often hear being kind of misunderstood 60 00:02:30,360 --> 00:02:36,239 and misrepresented it is essentially you 61 00:02:33,660 --> 00:02:39,239 only Define something once 62 00:02:36,239 --> 00:02:41,220 you only Define it once 63 00:02:39,239 --> 00:02:43,260 that might be a meaningful value to 64 00:02:41,220 --> 00:02:46,019 which we give a name so that we can 65 00:02:43,260 --> 00:02:50,000 always reference it or that might be how 66 00:02:46,019 --> 00:02:50,000 to test or perform some function 67 00:02:50,340 --> 00:02:54,060 but the benefit of defining it once 68 00:02:52,440 --> 00:02:57,360 means that we can correct it in one 69 00:02:54,060 --> 00:03:00,840 place and it's corrected everywhere 70 00:02:57,360 --> 00:03:01,980 another major factor of this is that 71 00:03:00,840 --> 00:03:04,140 ideally 72 00:03:01,980 --> 00:03:06,120 from the Zen of python everybody reads 73 00:03:04,140 --> 00:03:08,160 this don't we 74 00:03:06,120 --> 00:03:11,700 there should be one and preferably only 75 00:03:08,160 --> 00:03:13,680 one obvious way to do something 76 00:03:11,700 --> 00:03:16,200 now let's just brief overview of what an 77 00:03:13,680 --> 00:03:17,879 HTTP request looks like and I've just 78 00:03:16,200 --> 00:03:18,720 seen a typo 79 00:03:17,879 --> 00:03:21,599 um 80 00:03:18,720 --> 00:03:24,300 you have the headers in blue here the 81 00:03:21,599 --> 00:03:26,220 request path what's being requested and 82 00:03:24,300 --> 00:03:28,080 then the content of requests this is 83 00:03:26,220 --> 00:03:29,760 actually a sample post that I copied 84 00:03:28,080 --> 00:03:34,200 from somewhere else just to see what's 85 00:03:29,760 --> 00:03:36,540 in it so in an HTTP request object 86 00:03:34,200 --> 00:03:38,519 we reflect this and there are three main 87 00:03:36,540 --> 00:03:40,980 groups of functionality 88 00:03:38,519 --> 00:03:44,159 there's handling headers 89 00:03:40,980 --> 00:03:46,260 there's handling URLs and paths 90 00:03:44,159 --> 00:03:47,519 and then there's content handling and 91 00:03:46,260 --> 00:03:49,819 these are the three sections I'm going 92 00:03:47,519 --> 00:03:49,819 to address 93 00:03:49,920 --> 00:03:54,360 so 94 00:03:51,180 --> 00:03:56,700 first with headers well Django makes 95 00:03:54,360 --> 00:03:59,099 that really easy to access we have this 96 00:03:56,700 --> 00:04:01,500 nice cached object called HTTP headers 97 00:03:59,099 --> 00:04:03,420 which holds all of our headers so when 98 00:04:01,500 --> 00:04:06,720 you you don't have to dig through the 99 00:04:03,420 --> 00:04:09,120 meta object to find any of it 100 00:04:06,720 --> 00:04:11,280 now Django also here is protecting us 101 00:04:09,120 --> 00:04:14,700 from a lot of tedious things 102 00:04:11,280 --> 00:04:16,019 so for instance if anybody's worked with 103 00:04:14,700 --> 00:04:17,579 Django for a long time you might 104 00:04:16,019 --> 00:04:19,320 remember having to dig into the meta 105 00:04:17,579 --> 00:04:21,120 object to find a lot of details of stuff 106 00:04:19,320 --> 00:04:21,900 that you might have learned along the 107 00:04:21,120 --> 00:04:25,139 way 108 00:04:21,900 --> 00:04:28,380 that some headers have an HTTP prefix 109 00:04:25,139 --> 00:04:30,419 and some do not so Django remembers this 110 00:04:28,380 --> 00:04:33,320 and deals with it for you so you don't 111 00:04:30,419 --> 00:04:33,320 have to remember that 112 00:04:33,360 --> 00:04:38,220 additionally 113 00:04:34,820 --> 00:04:42,660 HTTP specifies using hyphens between 114 00:04:38,220 --> 00:04:44,940 words whiskey supports using underscores 115 00:04:42,660 --> 00:04:47,040 so again Django is protecting us from 116 00:04:44,940 --> 00:04:48,840 this common mistake so we don't have to 117 00:04:47,040 --> 00:04:50,820 remember either way 118 00:04:48,840 --> 00:04:52,500 has actually got when it parses the 119 00:04:50,820 --> 00:04:54,660 header name it replaces all the 120 00:04:52,500 --> 00:04:56,520 underscores with hyphens and it 121 00:04:54,660 --> 00:04:58,500 remembers to remove 122 00:04:56,520 --> 00:04:59,400 the prefix only for the ones they have 123 00:04:58,500 --> 00:05:01,919 it 124 00:04:59,400 --> 00:05:03,660 and when you ask for a header it's also 125 00:05:01,919 --> 00:05:05,940 very forgiving in allowing you to use 126 00:05:03,660 --> 00:05:07,440 underscores or hyphens it'll work either 127 00:05:05,940 --> 00:05:08,639 way 128 00:05:07,440 --> 00:05:10,680 [Applause] 129 00:05:08,639 --> 00:05:13,259 next 130 00:05:10,680 --> 00:05:15,120 handling the content type header every 131 00:05:13,259 --> 00:05:19,380 almost all requests will come with a 132 00:05:15,120 --> 00:05:21,240 content type header and if we get one 133 00:05:19,380 --> 00:05:22,740 it can give us a lot of useful details 134 00:05:21,240 --> 00:05:26,039 so we can see here it's telling us this 135 00:05:22,740 --> 00:05:28,259 is an HTML content and in fact 136 00:05:26,039 --> 00:05:31,080 oh that hasn't formatted well and in 137 00:05:28,259 --> 00:05:33,060 fact it's it's utf-8 encoded or it might 138 00:05:31,080 --> 00:05:35,900 be a multi-part form data and it needs a 139 00:05:33,060 --> 00:05:35,900 particular boundary 140 00:05:36,300 --> 00:05:40,440 so we need a way to grab that 141 00:05:38,580 --> 00:05:44,100 information and parse it out and 142 00:05:40,440 --> 00:05:46,259 fortunately this is all done for us 143 00:05:44,100 --> 00:05:48,360 additionally 144 00:05:46,259 --> 00:05:50,759 we have a function for parsing the 145 00:05:48,360 --> 00:05:52,500 headers additionally Django will go and 146 00:05:50,759 --> 00:05:54,000 say hey if you told us what the 147 00:05:52,500 --> 00:05:56,340 character set is if you told us the 148 00:05:54,000 --> 00:05:58,440 encoding we'll go and find it and 149 00:05:56,340 --> 00:06:01,020 remember what that encoding is we're 150 00:05:58,440 --> 00:06:03,600 going to need that later on 151 00:06:01,020 --> 00:06:06,000 this used to use the CGI pars header 152 00:06:03,600 --> 00:06:08,580 function from the standard Library which 153 00:06:06,000 --> 00:06:10,320 was one of my earliest comic commits to 154 00:06:08,580 --> 00:06:13,139 Django but that whole package has been 155 00:06:10,320 --> 00:06:15,900 deprecated so it's on the way out 156 00:06:13,139 --> 00:06:18,539 the accept header tells is the client 157 00:06:15,900 --> 00:06:20,100 telling the server I would like in order 158 00:06:18,539 --> 00:06:22,020 of preference 159 00:06:20,100 --> 00:06:24,600 these different content types I'm happy 160 00:06:22,020 --> 00:06:26,819 to deal with them so again Django has a 161 00:06:24,600 --> 00:06:28,680 class to help parse all of that out and 162 00:06:26,819 --> 00:06:30,720 hand them back to you in a state that's 163 00:06:28,680 --> 00:06:32,160 much easier for you to use you don't 164 00:06:30,720 --> 00:06:33,840 have to remember how to parse that 165 00:06:32,160 --> 00:06:34,919 header you don't have to remember how to 166 00:06:33,840 --> 00:06:37,139 interpret it 167 00:06:34,919 --> 00:06:40,319 but even better than this 168 00:06:37,139 --> 00:06:42,539 it exposes all of those as cached 169 00:06:40,319 --> 00:06:44,759 property for you to access as a list and 170 00:06:42,539 --> 00:06:47,759 then gives you a nice convenient 171 00:06:44,759 --> 00:06:50,759 function to say hey are they okay with 172 00:06:47,759 --> 00:06:53,639 me giving them this response type 173 00:06:50,759 --> 00:06:55,080 none of these are very complex functions 174 00:06:53,639 --> 00:06:57,000 but all of them are ones you could 175 00:06:55,080 --> 00:07:00,800 subtly get wrong if you weren't paying 176 00:06:57,000 --> 00:07:00,800 attention every time so here they are 177 00:07:00,840 --> 00:07:05,340 so next is the host header 178 00:07:03,600 --> 00:07:07,199 which is 179 00:07:05,340 --> 00:07:09,380 how do we know 180 00:07:07,199 --> 00:07:13,319 who the client thinks they're talking to 181 00:07:09,380 --> 00:07:15,900 when multi-site hosting came along this 182 00:07:13,319 --> 00:07:17,639 was essential now it's just natural and 183 00:07:15,900 --> 00:07:20,099 standard for everywhere 184 00:07:17,639 --> 00:07:22,020 we learned this by asking well what was 185 00:07:20,099 --> 00:07:25,080 the server name that we that we believe 186 00:07:22,020 --> 00:07:26,699 is our name or what was the host header 187 00:07:25,080 --> 00:07:28,620 that the Reliance sent in their request 188 00:07:26,699 --> 00:07:31,380 or 189 00:07:28,620 --> 00:07:34,680 actually maybe we're behind a proxy and 190 00:07:31,380 --> 00:07:36,900 so the proxy is telling us 191 00:07:34,680 --> 00:07:38,759 who their request who they were accessed 192 00:07:36,900 --> 00:07:40,560 as and though who we're forwarding for 193 00:07:38,759 --> 00:07:42,360 so we've got to be able to resolve all 194 00:07:40,560 --> 00:07:44,280 of this 195 00:07:42,360 --> 00:07:45,780 you might forget that sometimes you 196 00:07:44,280 --> 00:07:47,460 might do try and take a shortcut 197 00:07:45,780 --> 00:07:49,380 sometimes and then the system changes 198 00:07:47,460 --> 00:07:52,259 and you don't keep up so 199 00:07:49,380 --> 00:07:54,660 Django takes care of that for us it has 200 00:07:52,259 --> 00:07:56,460 a thing and says okay if you're using X 201 00:07:54,660 --> 00:07:58,500 forwarded for then we'll use it if it's 202 00:07:56,460 --> 00:08:00,240 present and if that's not there we'll 203 00:07:58,500 --> 00:08:01,620 use host and if not there we'll use our 204 00:08:00,240 --> 00:08:03,479 own server name and then we'll add the 205 00:08:01,620 --> 00:08:05,520 ports if it's non-standing 206 00:08:03,479 --> 00:08:07,560 all these little corner cases it's just 207 00:08:05,520 --> 00:08:11,160 protecting you from 208 00:08:07,560 --> 00:08:12,960 oh and this self is secure down at the 209 00:08:11,160 --> 00:08:14,819 bottom there which we saw earlier is a 210 00:08:12,960 --> 00:08:18,979 trivial little function but again test 211 00:08:14,819 --> 00:08:18,979 it once write it once don't redefine it 212 00:08:19,080 --> 00:08:23,759 going further with the host option 213 00:08:21,660 --> 00:08:25,440 get host now protects you from the 214 00:08:23,759 --> 00:08:27,060 dangerous things we've seen the tedious 215 00:08:25,440 --> 00:08:28,979 protection but there's also dangerous 216 00:08:27,060 --> 00:08:30,780 what if that's not the host we think we 217 00:08:28,979 --> 00:08:33,120 are what if that's a host name that we 218 00:08:30,780 --> 00:08:35,399 don't think we should be answering to 219 00:08:33,120 --> 00:08:37,560 so Django includes the functionality for 220 00:08:35,399 --> 00:08:40,680 the allowed hosts list which was a known 221 00:08:37,560 --> 00:08:42,300 attack back in the mid to early 20s 222 00:08:40,680 --> 00:08:44,159 2000s 223 00:08:42,300 --> 00:08:46,080 and if it doesn't match and if it's not 224 00:08:44,159 --> 00:08:48,380 a valid List It protects you from that 225 00:08:46,080 --> 00:08:48,380 Danger 226 00:08:48,480 --> 00:08:53,300 our next step is URL buildings 227 00:08:53,459 --> 00:08:58,680 what was the path that the user actually 228 00:08:56,160 --> 00:09:00,360 asked for 229 00:08:58,680 --> 00:09:02,220 well we've got two functions for getting 230 00:09:00,360 --> 00:09:03,839 that which is subtly different in ways 231 00:09:02,220 --> 00:09:05,519 that are detailed but the ones to do 232 00:09:03,839 --> 00:09:07,680 with the full path the ones to do with 233 00:09:05,519 --> 00:09:09,600 the path that chango's handling in case 234 00:09:07,680 --> 00:09:12,300 we're on a subpath and so on 235 00:09:09,600 --> 00:09:14,820 so under the hood these are both calling 236 00:09:12,300 --> 00:09:16,620 this function get full path which is 237 00:09:14,820 --> 00:09:18,360 doing actually a surprising amount of 238 00:09:16,620 --> 00:09:20,120 work for what you'd think would be a 239 00:09:18,360 --> 00:09:23,459 very simple thing get me the path 240 00:09:20,120 --> 00:09:26,040 anybody here remember the late 90s with 241 00:09:23,459 --> 00:09:27,920 ie and all of its path attacks and and 242 00:09:26,040 --> 00:09:29,459 uh 243 00:09:27,920 --> 00:09:32,160 exploits 244 00:09:29,459 --> 00:09:33,540 no well yep that's a couple of people as 245 00:09:32,160 --> 00:09:35,640 old as me 246 00:09:33,540 --> 00:09:37,019 um it was a common problem and it was a 247 00:09:35,640 --> 00:09:39,000 problem that I had turned up again and 248 00:09:37,019 --> 00:09:40,740 again and again because this solution 249 00:09:39,000 --> 00:09:42,660 wasn't centralized 250 00:09:40,740 --> 00:09:45,000 so here Django is going through and it's 251 00:09:42,660 --> 00:09:46,380 making sure that your iPath is escaped 252 00:09:45,000 --> 00:09:47,820 properly it's making sure there's a 253 00:09:46,380 --> 00:09:50,160 slash if we think there should always be 254 00:09:47,820 --> 00:09:51,660 a slash if there's a query string we're 255 00:09:50,160 --> 00:09:54,120 going to include that and put that in 256 00:09:51,660 --> 00:09:56,519 properly with a question mark and 257 00:09:54,120 --> 00:09:59,339 dealing with all of those problems again 258 00:09:56,519 --> 00:10:02,720 remembering to do every step that we 259 00:09:59,339 --> 00:10:02,720 might forget to do sometimes 260 00:10:03,660 --> 00:10:08,640 next 261 00:10:05,279 --> 00:10:10,260 game is it HTTP is it https is it 262 00:10:08,640 --> 00:10:12,839 something else are we getting confused 263 00:10:10,260 --> 00:10:14,940 well there's a request dot scheme there 264 00:10:12,839 --> 00:10:16,620 okay 265 00:10:14,940 --> 00:10:18,959 there's a lot hidden behind that of 266 00:10:16,620 --> 00:10:20,760 course much like host there might be 267 00:10:18,959 --> 00:10:23,640 proxies in the way there might be other 268 00:10:20,760 --> 00:10:27,120 things that changing how we resolve this 269 00:10:23,640 --> 00:10:29,459 so again Django takes the best way to do 270 00:10:27,120 --> 00:10:32,899 this wraps it up in a function and 271 00:10:29,459 --> 00:10:32,899 protects us from that tedium 272 00:10:36,140 --> 00:10:41,220 and you can see here if we're told to 273 00:10:39,240 --> 00:10:43,260 and you can turn on and off different 274 00:10:41,220 --> 00:10:44,760 options and different features but it 275 00:10:43,260 --> 00:10:48,060 will make sure that we get one of those 276 00:10:44,760 --> 00:10:50,040 two answers and if not 277 00:10:48,060 --> 00:10:52,320 the last step there 278 00:10:50,040 --> 00:10:54,540 is a hook so that the localized 279 00:10:52,320 --> 00:10:56,640 implementation is depending on whether 280 00:10:54,540 --> 00:11:00,420 you're using whiskey asgi or some other 281 00:10:56,640 --> 00:11:03,360 actual transport host or interface layer 282 00:11:00,420 --> 00:11:05,339 can hook in and say well this is how I 283 00:11:03,360 --> 00:11:07,320 think it should be implemented as it 284 00:11:05,339 --> 00:11:09,660 turns out whiskey and asgi have subtly 285 00:11:07,320 --> 00:11:11,459 different ways of doing this 286 00:11:09,660 --> 00:11:15,300 in whiskey we get it from the 287 00:11:11,459 --> 00:11:18,720 environment that's posted us in asgi 288 00:11:15,300 --> 00:11:20,880 we ask the scope 289 00:11:18,720 --> 00:11:23,180 and then otherwise we fall back to the 290 00:11:20,880 --> 00:11:23,180 default 291 00:11:23,959 --> 00:11:29,820 next is absolute URLs so sometimes you 292 00:11:27,720 --> 00:11:32,760 want to include the entire host name the 293 00:11:29,820 --> 00:11:34,320 entire scheme all of the way so that you 294 00:11:32,760 --> 00:11:38,040 could for instance embed it in an email 295 00:11:34,320 --> 00:11:39,779 so on so again a lot of tedium a lot of 296 00:11:38,040 --> 00:11:41,760 steps that you might forget Django 297 00:11:39,779 --> 00:11:43,680 remembers them first it calls get full 298 00:11:41,760 --> 00:11:45,000 path like we saw before which makes sure 299 00:11:43,680 --> 00:11:46,860 that everything's encoded properly and 300 00:11:45,000 --> 00:11:49,140 constructed properly then it actually 301 00:11:46,860 --> 00:11:51,120 parses what it got out of that 302 00:11:49,140 --> 00:11:53,160 so they can make sure it fills in the 303 00:11:51,120 --> 00:11:55,019 scheme and the host name or net lock as 304 00:11:53,160 --> 00:11:57,240 it calls it in case they haven't been 305 00:11:55,019 --> 00:11:59,339 provided 306 00:11:57,240 --> 00:12:01,380 make sure to clean up and resolve all 307 00:11:59,339 --> 00:12:03,720 the relative pathing for dot dot slash 308 00:12:01,380 --> 00:12:06,660 and so on and finally 309 00:12:03,720 --> 00:12:08,100 iri to URI encoding because we can't 310 00:12:06,660 --> 00:12:10,140 necessarily give people International 311 00:12:08,100 --> 00:12:12,480 codes we have to encode it properly for 312 00:12:10,140 --> 00:12:14,880 consumption on the web 313 00:12:12,480 --> 00:12:16,320 and just a taste of how fiddly this can 314 00:12:14,880 --> 00:12:18,300 get 315 00:12:16,320 --> 00:12:21,959 this is one part of the function that's 316 00:12:18,300 --> 00:12:24,540 doing it and it's remembering to tick 317 00:12:21,959 --> 00:12:26,579 does the path start with Slash does it 318 00:12:24,540 --> 00:12:28,380 have you know do we have a Celine do we 319 00:12:26,579 --> 00:12:30,060 have net lock do we have dot dot in 320 00:12:28,380 --> 00:12:32,399 there do we have dot slash in there and 321 00:12:30,060 --> 00:12:36,019 so on or all these little corner cases 322 00:12:32,399 --> 00:12:36,019 that be very easy to forget 323 00:12:36,600 --> 00:12:42,480 okay next we have content handling 324 00:12:40,019 --> 00:12:45,300 we've got reading the whole raw body or 325 00:12:42,480 --> 00:12:47,579 maybe iterating rows of data or reading 326 00:12:45,300 --> 00:12:49,740 and parsing the content or handling the 327 00:12:47,579 --> 00:12:51,779 past content like form data and files 328 00:12:49,740 --> 00:12:53,279 and so on all of that is stuff that 329 00:12:51,779 --> 00:12:54,779 needs to be taken care of all of that 330 00:12:53,279 --> 00:12:57,600 would be tedious if you had to remember 331 00:12:54,779 --> 00:13:00,240 how to do it every time 332 00:12:57,600 --> 00:13:02,700 handling the body the request object 333 00:13:00,240 --> 00:13:04,860 works like a file so you can access it 334 00:13:02,700 --> 00:13:06,720 with read read line read lines you can 335 00:13:04,860 --> 00:13:08,940 iterate it to get lines of data out all 336 00:13:06,720 --> 00:13:11,399 of that is wrapped up for you and 337 00:13:08,940 --> 00:13:13,740 additionally there's request.body which 338 00:13:11,399 --> 00:13:17,279 if you ask for that grabs all of the 339 00:13:13,740 --> 00:13:19,980 requests as a single data blob byte 340 00:13:17,279 --> 00:13:23,040 string so that you can just do whatever 341 00:13:19,980 --> 00:13:24,899 you like with it anyone who uses drf 342 00:13:23,040 --> 00:13:27,800 this is how it gets the data so that it 343 00:13:24,899 --> 00:13:27,800 can parse the Json 344 00:13:28,440 --> 00:13:32,579 now this is all wrapped inside a 345 00:13:30,720 --> 00:13:34,920 property which has a more defensive 346 00:13:32,579 --> 00:13:36,600 stuff inside there so that it'll try to 347 00:13:34,920 --> 00:13:38,700 protect you from things like if you read 348 00:13:36,600 --> 00:13:40,139 a few lines of data and then do an 349 00:13:38,700 --> 00:13:43,079 operation that's supposed to operate on 350 00:13:40,139 --> 00:13:45,660 the whole body that's a mistake almost 351 00:13:43,079 --> 00:13:47,820 certainly so it catches that and warns 352 00:13:45,660 --> 00:13:51,000 you it will raise an error it also 353 00:13:47,820 --> 00:13:52,860 enforces the maximum data upload size so 354 00:13:51,000 --> 00:13:55,380 that if somebody sends you a very very 355 00:13:52,860 --> 00:13:57,300 large post it will spool it out to disk 356 00:13:55,380 --> 00:13:58,860 or handle it some other way so that it 357 00:13:57,300 --> 00:14:00,899 doesn't exhaust the memory and can't be 358 00:13:58,860 --> 00:14:03,480 used as an attack Vector protecting you 359 00:14:00,899 --> 00:14:06,120 from the dangerous things 360 00:14:03,480 --> 00:14:08,040 our next step is content encoding as we 361 00:14:06,120 --> 00:14:09,899 saw earlier the client can tell us about 362 00:14:08,040 --> 00:14:11,519 the content type and we need to make 363 00:14:09,899 --> 00:14:13,519 sure that we 364 00:14:11,519 --> 00:14:16,200 parse all of the content in the body 365 00:14:13,519 --> 00:14:18,600 according to that content type 366 00:14:16,200 --> 00:14:21,420 so when we receive it and when we set 367 00:14:18,600 --> 00:14:23,519 that content type we have to rethink 368 00:14:21,420 --> 00:14:26,579 about how we're parsing the get and and 369 00:14:23,519 --> 00:14:30,420 body the post data accordingly so when 370 00:14:26,579 --> 00:14:33,660 you set the encoding Django remembers 371 00:14:30,420 --> 00:14:35,880 to clear out the if if it's paused to 372 00:14:33,660 --> 00:14:37,139 get in post data clear it out so the 373 00:14:35,880 --> 00:14:40,820 next time you access it will be 374 00:14:37,139 --> 00:14:40,820 re-parsed with the correct encoding 375 00:14:41,160 --> 00:14:45,980 so next we have handling of post data 376 00:14:46,260 --> 00:14:52,019 this will be parsing posted data and it 377 00:14:50,040 --> 00:14:54,180 is pretty common practice there's a 378 00:14:52,019 --> 00:14:55,680 standard function for it in J in Python 379 00:14:54,180 --> 00:14:57,839 but Django does it a little differently 380 00:14:55,680 --> 00:14:59,339 to extract the files out for you 381 00:14:57,839 --> 00:15:01,199 but also we've got to make sure what 382 00:14:59,339 --> 00:15:03,180 what if the body was sent to us with the 383 00:15:01,199 --> 00:15:05,339 wrong content type we don't want to be 384 00:15:03,180 --> 00:15:06,899 treating every post like its form data 385 00:15:05,339 --> 00:15:09,779 when it isn't and there's two different 386 00:15:06,899 --> 00:15:12,000 ways of encoding form data so it's all 387 00:15:09,779 --> 00:15:14,160 right Django's got you covered 388 00:15:12,000 --> 00:15:15,300 when it has to load the post data and 389 00:15:14,160 --> 00:15:18,120 the files 390 00:15:15,300 --> 00:15:18,959 it goes and checks is this actually a 391 00:15:18,120 --> 00:15:21,360 post 392 00:15:18,959 --> 00:15:23,220 if it's not a post don't do it we'll 393 00:15:21,360 --> 00:15:25,139 just put in some empty values and move 394 00:15:23,220 --> 00:15:27,540 on with life 395 00:15:25,139 --> 00:15:30,360 next it'll check 396 00:15:27,540 --> 00:15:31,920 have we actually started reading the 397 00:15:30,360 --> 00:15:34,320 content already 398 00:15:31,920 --> 00:15:37,560 then that's a mistake and we're going to 399 00:15:34,320 --> 00:15:40,019 flag that and raise an error 400 00:15:37,560 --> 00:15:41,820 finally we'll go and say okay what 401 00:15:40,019 --> 00:15:43,820 format is it is it a multi-part form 402 00:15:41,820 --> 00:15:45,959 data yep then we've got to go parse it 403 00:15:43,820 --> 00:15:47,760 have we already read all of the body 404 00:15:45,959 --> 00:15:49,920 then we'll go and use that deposit have 405 00:15:47,760 --> 00:15:51,540 we already done this again saving you 406 00:15:49,920 --> 00:15:53,459 from those things you might forget later 407 00:15:51,540 --> 00:15:56,459 on when the system changes 408 00:15:53,459 --> 00:15:58,680 and finally the other content types in 409 00:15:56,459 --> 00:16:00,240 case they handled one is it X form URL 410 00:15:58,680 --> 00:16:03,600 encoded which means it looks just like a 411 00:16:00,240 --> 00:16:05,279 query string and the last case is 412 00:16:03,600 --> 00:16:06,600 we don't know what to do with it it's a 413 00:16:05,279 --> 00:16:09,980 content type we don't understand so 414 00:16:06,600 --> 00:16:09,980 we'll just give you an empty content 415 00:16:10,620 --> 00:16:16,079 and also I mentioned file handling so 416 00:16:13,800 --> 00:16:17,519 who wants to remember how to pass files 417 00:16:16,079 --> 00:16:19,740 out of the form 418 00:16:17,519 --> 00:16:22,320 who wants to handle that 419 00:16:19,740 --> 00:16:25,380 just do it once do it right what about 420 00:16:22,320 --> 00:16:28,139 if somebody sends you an enormous file 421 00:16:25,380 --> 00:16:30,300 again let's put a limit there let's have 422 00:16:28,139 --> 00:16:31,680 Django's handles go I can handle that if 423 00:16:30,300 --> 00:16:32,699 it's really big I'll spool it out to 424 00:16:31,680 --> 00:16:34,680 disk and you'll never know the 425 00:16:32,699 --> 00:16:36,720 difference 426 00:16:34,680 --> 00:16:38,399 so to handle that we have upload 427 00:16:36,720 --> 00:16:40,860 handlers 428 00:16:38,399 --> 00:16:42,420 you can ask for a list of upload 429 00:16:40,860 --> 00:16:43,980 handlers if you never touch them they 430 00:16:42,420 --> 00:16:46,019 don't happen a lot of the things in 431 00:16:43,980 --> 00:16:47,639 requests are lazy so that we're not 432 00:16:46,019 --> 00:16:48,899 doing work if we're never going to need 433 00:16:47,639 --> 00:16:50,940 it 434 00:16:48,899 --> 00:16:52,680 if the upload handlers have been not 435 00:16:50,940 --> 00:16:54,540 been set then we'll go and run through 436 00:16:52,680 --> 00:16:56,820 and initialize them which does a whole 437 00:16:54,540 --> 00:16:58,680 bunch of let's get what you specified in 438 00:16:56,820 --> 00:17:00,720 the settings file and go and ask all of 439 00:16:58,680 --> 00:17:02,880 them to get ready 440 00:17:00,720 --> 00:17:04,919 But ultimately you're still in control 441 00:17:02,880 --> 00:17:06,480 you can override the default set of 442 00:17:04,919 --> 00:17:09,199 upload handlers for your view if you 443 00:17:06,480 --> 00:17:09,199 have a special need 444 00:17:10,559 --> 00:17:14,520 and the last part of this section which 445 00:17:12,720 --> 00:17:16,020 somehow has a lot quicker to talk about 446 00:17:14,520 --> 00:17:18,240 this time when I tell you than when I 447 00:17:16,020 --> 00:17:20,540 did this run last time is handling 448 00:17:18,240 --> 00:17:20,540 cookies 449 00:17:22,020 --> 00:17:25,980 does everybody remember all the 450 00:17:23,520 --> 00:17:28,640 subtleties of how to pause a cookie 451 00:17:25,980 --> 00:17:28,640 correct 452 00:17:29,520 --> 00:17:33,480 so again Django takes care of it for you 453 00:17:32,040 --> 00:17:35,039 it's a tedious thing it's a thing you 454 00:17:33,480 --> 00:17:36,480 might make mistakes with it's the thing 455 00:17:35,039 --> 00:17:38,220 that we don't want to have to deal with 456 00:17:36,480 --> 00:17:40,260 we just want to get the answers that we 457 00:17:38,220 --> 00:17:42,660 want so here it is it's all taken care 458 00:17:40,260 --> 00:17:44,400 of for you 459 00:17:42,660 --> 00:17:46,799 there's actually a cooking handle 460 00:17:44,400 --> 00:17:48,720 handling Library built into python but 461 00:17:46,799 --> 00:17:50,340 Django does a bit more on top of that 462 00:17:48,720 --> 00:17:53,760 just to make life a little more a little 463 00:17:50,340 --> 00:17:55,200 safer and finally Django includes a 464 00:17:53,760 --> 00:17:56,700 bunch of signed cookie handling 465 00:17:55,200 --> 00:17:58,679 functionality 466 00:17:56,700 --> 00:18:00,179 why would you need signed cookies well I 467 00:17:58,679 --> 00:18:02,280 mean cookies are stored in the browser 468 00:18:00,179 --> 00:18:04,440 for a start so who means your trusting 469 00:18:02,280 --> 00:18:06,360 information from the client is cookies 470 00:18:04,440 --> 00:18:09,240 have a lot of rules 471 00:18:06,360 --> 00:18:11,760 about how the browser handles them who 472 00:18:09,240 --> 00:18:15,120 they should show them to you know is it 473 00:18:11,760 --> 00:18:17,460 HTTP only is it only in Secure contacts 474 00:18:15,120 --> 00:18:20,100 is it only to be used when talking to 475 00:18:17,460 --> 00:18:21,480 the same site should we allow JavaScript 476 00:18:20,100 --> 00:18:23,820 to read it 477 00:18:21,480 --> 00:18:25,919 so you know there's a lot of rules there 478 00:18:23,820 --> 00:18:28,799 that's great 479 00:18:25,919 --> 00:18:30,419 Miss Koreans don't play by the rules so 480 00:18:28,799 --> 00:18:32,220 just because the browser might do all 481 00:18:30,419 --> 00:18:36,000 the right things doesn't mean that the 482 00:18:32,220 --> 00:18:38,220 client is talking to you is a browser 483 00:18:36,000 --> 00:18:40,200 so as a result 484 00:18:38,220 --> 00:18:43,080 Django includes 485 00:18:40,200 --> 00:18:45,240 get signed cookie 486 00:18:43,080 --> 00:18:47,100 cat sign cookie 487 00:18:45,240 --> 00:18:48,660 does exactly what it says it will take 488 00:18:47,100 --> 00:18:50,460 the cookie that you've asked for and 489 00:18:48,660 --> 00:18:52,799 then make sure that the content in there 490 00:18:50,460 --> 00:18:54,900 has been signed with the secret key that 491 00:18:52,799 --> 00:18:57,419 you keep in your setup so you're able to 492 00:18:54,900 --> 00:18:59,400 set a cookie with content that the 493 00:18:57,419 --> 00:19:01,140 client can see as much as they want but 494 00:18:59,400 --> 00:19:03,960 if they modify it you can reject it 495 00:19:01,140 --> 00:19:06,539 immediately out of hand 496 00:19:03,960 --> 00:19:08,039 okay and as I said this went a lot 497 00:19:06,539 --> 00:19:10,020 quicker than last time I did this last 498 00:19:08,039 --> 00:19:13,500 time it went over 30 minutes 499 00:19:10,020 --> 00:19:16,940 whereas now I am done 500 00:19:13,500 --> 00:19:16,940 that was surprisingly quick 501 00:19:17,160 --> 00:19:20,880 I'm guessing it's the nervous energy 502 00:19:18,720 --> 00:19:22,500 speeding me up 503 00:19:20,880 --> 00:19:24,240 you see with being done early now you 504 00:19:22,500 --> 00:19:26,400 can field questions now I can feel it 505 00:19:24,240 --> 00:19:28,919 questions oh wow 506 00:19:26,400 --> 00:19:32,419 have we got 10 minutes of questions 507 00:19:28,919 --> 00:19:32,419 excellent not Russell yeah 508 00:19:33,419 --> 00:19:37,860 hello test 509 00:19:35,280 --> 00:19:39,600 um you mentioned uh Jagger does a little 510 00:19:37,860 --> 00:19:41,880 more with cookies than the standard 511 00:19:39,600 --> 00:19:43,200 Library just interested well anything 512 00:19:41,880 --> 00:19:45,360 interesting in there that you're doing 513 00:19:43,200 --> 00:19:47,220 that the standard Library doesn't it 514 00:19:45,360 --> 00:19:50,039 does mention a few interesting quirks 515 00:19:47,220 --> 00:19:50,820 and bugs uh cited in 516 00:19:50,039 --> 00:19:54,660 um 517 00:19:50,820 --> 00:19:56,400 Mozilla Dev Network as for why it it 518 00:19:54,660 --> 00:19:58,260 handles things a little quercally it's 519 00:19:56,400 --> 00:20:01,140 basically again to protect you from 520 00:19:58,260 --> 00:20:03,419 dangerous mistakes around the world of 521 00:20:01,140 --> 00:20:05,940 not every client is implementing their 522 00:20:03,419 --> 00:20:08,460 cookies correctly in fact if if anybody 523 00:20:05,940 --> 00:20:10,440 has been around you long enough you'll 524 00:20:08,460 --> 00:20:13,679 know that in the early days cookies were 525 00:20:10,440 --> 00:20:15,860 not a standardized thing at all Netscape 526 00:20:13,679 --> 00:20:19,500 introduced them 527 00:20:15,860 --> 00:20:21,120 there were wild wild west concept of how 528 00:20:19,500 --> 00:20:22,860 they were encoded in format and what the 529 00:20:21,120 --> 00:20:25,740 different fields meant and then they 530 00:20:22,860 --> 00:20:27,960 only got standardized a lot later on and 531 00:20:25,740 --> 00:20:29,880 so some of those are still a bit quirky 532 00:20:27,960 --> 00:20:31,980 and it's protecting you from that I do 533 00:20:29,880 --> 00:20:33,660 recommend by the way as an adjunct to 534 00:20:31,980 --> 00:20:37,640 that that everybody have a look through 535 00:20:33,660 --> 00:20:40,620 the HTTP request content because it is 536 00:20:37,640 --> 00:20:42,299 really quite easy to read in most cases 537 00:20:40,620 --> 00:20:44,940 and very well commented as you saw in 538 00:20:42,299 --> 00:20:47,160 some of those bits 539 00:20:44,940 --> 00:20:49,580 does anybody else have a question oh 540 00:20:47,160 --> 00:20:49,580 fantastic 541 00:20:50,160 --> 00:20:55,020 hey um 542 00:20:52,080 --> 00:20:57,539 what other are you able to draw any 543 00:20:55,020 --> 00:20:59,280 comparisons to other HTTP requests 544 00:20:57,539 --> 00:21:01,140 implementations that are in the python 545 00:20:59,280 --> 00:21:04,140 ecosystem like I guess flask would have 546 00:21:01,140 --> 00:21:06,720 one there's like Starlet things like 547 00:21:04,140 --> 00:21:10,919 that are they also are they working at 548 00:21:06,720 --> 00:21:13,500 the same layer are they similar things I 549 00:21:10,919 --> 00:21:15,600 have not delved deeply enough to see 550 00:21:13,500 --> 00:21:17,100 what's going on I did mean to include a 551 00:21:15,600 --> 00:21:18,660 little story at the beginning of this of 552 00:21:17,100 --> 00:21:21,840 what really got me interested in this 553 00:21:18,660 --> 00:21:23,520 which was some years ago I built as an 554 00:21:21,840 --> 00:21:25,559 experiment to learn new you know 555 00:21:23,520 --> 00:21:27,500 upcoming Technologies on the web I built 556 00:21:25,559 --> 00:21:30,299 a little web chat service 557 00:21:27,500 --> 00:21:33,419 in Django originally and then I moved it 558 00:21:30,299 --> 00:21:35,520 to being a raw whiskey service and on 559 00:21:33,419 --> 00:21:37,919 top of that I started learning that oh 560 00:21:35,520 --> 00:21:39,780 I've got to deal with encoding oh I've 561 00:21:37,919 --> 00:21:41,460 got to deal with breaking this on oh 562 00:21:39,780 --> 00:21:43,020 I've got to deal with that and going 563 00:21:41,460 --> 00:21:44,520 back to Django and going how did you 564 00:21:43,020 --> 00:21:46,140 deal with it how did you I didn't know 565 00:21:44,520 --> 00:21:48,120 you even did that or how did you deal 566 00:21:46,140 --> 00:21:49,740 with that and that's what got me on 567 00:21:48,120 --> 00:21:52,020 along the line so I know that flask 568 00:21:49,740 --> 00:21:55,440 Builds on top of workflow I believe 569 00:21:52,020 --> 00:21:57,120 who specializes in being exactly that I 570 00:21:55,440 --> 00:21:59,460 have not looked at how a lot of the 571 00:21:57,120 --> 00:22:00,840 other platforms are dealing with but I 572 00:21:59,460 --> 00:22:02,640 expect that you'll find a lot of 573 00:22:00,840 --> 00:22:04,620 similarity style it if I remember 574 00:22:02,640 --> 00:22:06,659 correctly was built by somebody who came 575 00:22:04,620 --> 00:22:09,600 from a Django background it's built by 576 00:22:06,659 --> 00:22:11,520 Tom Christie yeah yeah so I'm sure 577 00:22:09,600 --> 00:22:13,200 there'd be a lot of similar Concepts 578 00:22:11,520 --> 00:22:15,059 involved and a lot of the same 579 00:22:13,200 --> 00:22:17,280 philosophy in the background of let's 580 00:22:15,059 --> 00:22:19,140 protect you from that tedium and from 581 00:22:17,280 --> 00:22:21,659 that Danger 582 00:22:19,140 --> 00:22:23,580 I think I saw some hands over that way 583 00:22:21,659 --> 00:22:27,659 you know any other questions hands up 584 00:22:23,580 --> 00:22:31,620 for Curtis oh a lovely speaker 585 00:22:27,659 --> 00:22:33,600 Katie getting her steps in uh so Django 586 00:22:31,620 --> 00:22:35,700 has these layers has these extra apis to 587 00:22:33,600 --> 00:22:38,400 protect you from all the nasty edge 588 00:22:35,700 --> 00:22:40,740 cases and Corner cases of the spec 589 00:22:38,400 --> 00:22:43,380 are there any legitimate uses for going 590 00:22:40,740 --> 00:22:45,179 directly to the metal either if what's 591 00:22:43,380 --> 00:22:46,500 the decision process of deciding no hang 592 00:22:45,179 --> 00:22:48,179 on I don't want to use Django as 593 00:22:46,500 --> 00:22:50,520 processing here I actually need need to 594 00:22:48,179 --> 00:22:52,980 be dealing with the war request manually 595 00:22:50,520 --> 00:22:55,140 managing it myself 596 00:22:52,980 --> 00:22:57,179 um I would expect from my experience 597 00:22:55,140 --> 00:23:01,520 that those are very very Corner cases 598 00:22:57,179 --> 00:23:05,400 I've seen as a particular use case where 599 00:23:01,520 --> 00:23:07,740 uh for instance the CEO csrf processing 600 00:23:05,400 --> 00:23:10,380 was tripping content reading 601 00:23:07,740 --> 00:23:12,419 and we didn't want it to so we had to go 602 00:23:10,380 --> 00:23:14,400 and sort of sidestep a few things and 603 00:23:12,419 --> 00:23:16,200 say stop doing that let us take care of 604 00:23:14,400 --> 00:23:19,200 this 605 00:23:16,200 --> 00:23:21,299 um that was one 606 00:23:19,200 --> 00:23:23,820 um you would have to be I would expect 607 00:23:21,299 --> 00:23:26,220 in a particularly unusual scenario of 608 00:23:23,820 --> 00:23:27,900 your own engineering before any of these 609 00:23:26,220 --> 00:23:30,840 things really start to get heavily in 610 00:23:27,900 --> 00:23:32,640 the way but again Django lets you do it 611 00:23:30,840 --> 00:23:34,380 if you don't want to process that as the 612 00:23:32,640 --> 00:23:36,539 body don't access request.post or 613 00:23:34,380 --> 00:23:37,860 request.files and it won't try to parse 614 00:23:36,539 --> 00:23:40,260 the content if you want to read the 615 00:23:37,860 --> 00:23:42,020 content yourself you can and even if you 616 00:23:40,260 --> 00:23:44,940 do access 617 00:23:42,020 --> 00:23:47,640 request.body all of that content is held 618 00:23:44,940 --> 00:23:48,480 in the string i o object for you for 619 00:23:47,640 --> 00:23:50,460 later 620 00:23:48,480 --> 00:23:52,559 so that you can still get there if you 621 00:23:50,460 --> 00:23:53,880 want to request parse the headers 622 00:23:52,559 --> 00:23:55,860 yourself if you want to do all of that 623 00:23:53,880 --> 00:23:58,740 yourself it's still there it's still 624 00:23:55,860 --> 00:24:01,140 held it's just a layer on top rather 625 00:23:58,740 --> 00:24:03,000 augmenting rather than obstructing your 626 00:24:01,140 --> 00:24:05,299 access to all of the raw request 627 00:24:03,000 --> 00:24:05,299 information 628 00:24:05,880 --> 00:24:09,840 and just a reminder if you're joining us 629 00:24:07,440 --> 00:24:11,700 online please just use a Discord thread 630 00:24:09,840 --> 00:24:13,559 and type in any questions we can ask 631 00:24:11,700 --> 00:24:16,140 them here in real life but right now 632 00:24:13,559 --> 00:24:18,780 I'll pass the mic to another question 633 00:24:16,140 --> 00:24:20,880 just on site called East Curtis um are 634 00:24:18,780 --> 00:24:23,159 they something that is opaque within the 635 00:24:20,880 --> 00:24:26,640 browser or is it possible to use a sign 636 00:24:23,159 --> 00:24:29,159 Cookie From Within JavaScript perhaps 637 00:24:26,640 --> 00:24:33,600 uh no from what I can see it's it's 638 00:24:29,159 --> 00:24:35,760 simply signed with a Mac so it's your 639 00:24:33,600 --> 00:24:37,260 content with a Mac added on so you 640 00:24:35,760 --> 00:24:38,340 should be able to still read it and 641 00:24:37,260 --> 00:24:40,620 parse it 642 00:24:38,340 --> 00:24:43,799 from the client side 643 00:24:40,620 --> 00:24:45,780 but yeah if you modify it that's what 644 00:24:43,799 --> 00:24:48,539 they're detecting 645 00:24:45,780 --> 00:24:50,400 that's an interesting concept 646 00:24:48,539 --> 00:24:52,500 you could stop using jots and start 647 00:24:50,400 --> 00:24:54,960 using signed cookies instead there's one 648 00:24:52,500 --> 00:24:58,520 behind Judy 649 00:24:54,960 --> 00:24:58,520 highly available microphones 650 00:25:01,919 --> 00:25:05,640 um I could look this up in like two 651 00:25:03,659 --> 00:25:10,260 minutes but since we have time I'd like 652 00:25:05,640 --> 00:25:12,440 to ask since uh HTTP request headers are 653 00:25:10,260 --> 00:25:16,200 case insensitive 654 00:25:12,440 --> 00:25:19,500 do I have to call Dot lower to compare 655 00:25:16,200 --> 00:25:22,679 them to or does shanko for the for the 656 00:25:19,500 --> 00:25:25,020 header Keys yeah I will go back to the 657 00:25:22,679 --> 00:25:25,840 code there because it actually does 658 00:25:25,020 --> 00:25:29,010 thank you 659 00:25:25,840 --> 00:25:29,010 [Music] 660 00:25:32,940 --> 00:25:39,600 if you look here 661 00:25:36,020 --> 00:25:41,700 the last line of I can't highlight it 662 00:25:39,600 --> 00:25:44,340 easily the last line of that first Paz 663 00:25:41,700 --> 00:25:46,799 had a name function it calls title case 664 00:25:44,340 --> 00:25:48,840 on it so that will normalize all of the 665 00:25:46,799 --> 00:25:51,600 the casing 666 00:25:48,840 --> 00:25:52,980 so the first letter of each word is is 667 00:25:51,600 --> 00:25:55,640 capitalized and all the rest are 668 00:25:52,980 --> 00:25:55,640 lowercased 669 00:25:55,860 --> 00:25:58,400 um excellent 670 00:25:58,440 --> 00:26:02,279 but that does mean that looking up 671 00:26:00,360 --> 00:26:05,779 Mateen might uh 672 00:26:02,279 --> 00:26:05,779 might feel differently about it 673 00:26:06,600 --> 00:26:11,039 yes so it normalizes all of them to 674 00:26:08,940 --> 00:26:13,700 title case to keep it consistent and 675 00:26:11,039 --> 00:26:13,700 standardized 676 00:26:15,000 --> 00:26:18,960 question up the back there okay great I 677 00:26:17,340 --> 00:26:21,600 think we've got four more minutes so 678 00:26:18,960 --> 00:26:23,220 we'll fight for it Katie's Katie's 679 00:26:21,600 --> 00:26:24,240 rushing no no hold on one second I 680 00:26:23,220 --> 00:26:26,039 thought I was going to fight for it just 681 00:26:24,240 --> 00:26:28,559 for the online people 682 00:26:26,039 --> 00:26:31,080 when should I use Django and when should 683 00:26:28,559 --> 00:26:32,279 we consider one of the other python web 684 00:26:31,080 --> 00:26:36,500 Frameworks 685 00:26:32,279 --> 00:26:36,500 oh the Eternal loaded question 686 00:26:37,080 --> 00:26:40,440 um 687 00:26:38,400 --> 00:26:42,720 just quickly because I mean I've been 688 00:26:40,440 --> 00:26:45,600 using I've been using Django for so long 689 00:26:42,720 --> 00:26:47,520 that Django is just what I reach for 690 00:26:45,600 --> 00:26:50,640 um I experience of of other Frameworks 691 00:26:47,520 --> 00:26:52,440 such as flask is flask can be much 692 00:26:50,640 --> 00:26:53,940 lighter weight because you start with 693 00:26:52,440 --> 00:26:56,059 almost nothing built in 694 00:26:53,940 --> 00:26:58,559 but that tends to lead to down the track 695 00:26:56,059 --> 00:27:00,539 you construct you add on all the bits 696 00:26:58,559 --> 00:27:02,340 that you want in the end but that means 697 00:27:00,539 --> 00:27:03,960 the next project that you go to may 698 00:27:02,340 --> 00:27:06,779 choose to use different tools to answer 699 00:27:03,960 --> 00:27:08,520 the same solution so it's not your 700 00:27:06,779 --> 00:27:10,860 skills in a flask project aren't 701 00:27:08,520 --> 00:27:13,020 necessarily as fungible as on a Django 702 00:27:10,860 --> 00:27:14,940 project Starlet is built from the ground 703 00:27:13,020 --> 00:27:17,179 up to be asynchronous so if you want to 704 00:27:14,940 --> 00:27:19,980 be asynchronous and go the modern path 705 00:27:17,179 --> 00:27:21,840 that that's asynchronous native 706 00:27:19,980 --> 00:27:23,400 everywhere and because it was from 707 00:27:21,840 --> 00:27:25,880 somebody with a strong Django background 708 00:27:23,400 --> 00:27:28,200 now going to uh let's revisit the world 709 00:27:25,880 --> 00:27:30,299 it's entirely possible that they've 710 00:27:28,200 --> 00:27:32,279 stepped past some of the the clumsier 711 00:27:30,299 --> 00:27:33,779 bits that we may not want to continue 712 00:27:32,279 --> 00:27:36,840 hanging on to and they've been able to 713 00:27:33,779 --> 00:27:39,419 do it clean it really comes down to I 714 00:27:36,840 --> 00:27:42,659 find what you're most familiar with and 715 00:27:39,419 --> 00:27:45,059 uh if you have specialized needs 716 00:27:42,659 --> 00:27:46,320 which one will answer those those needs 717 00:27:45,059 --> 00:27:48,480 I don't 718 00:27:46,320 --> 00:27:50,940 feel that any one of them is necessarily 719 00:27:48,480 --> 00:27:52,679 particularly the best solution in any 720 00:27:50,940 --> 00:27:54,900 case or how to choose that depends 721 00:27:52,679 --> 00:27:58,740 mostly on on Personal Taste and and 722 00:27:54,900 --> 00:28:00,240 Community or um ecosystem you might find 723 00:27:58,740 --> 00:28:01,559 that there's a flask plug-in that does 724 00:28:00,240 --> 00:28:04,380 the thing you need or you might find 725 00:28:01,559 --> 00:28:06,900 that this is a style add-on that answers 726 00:28:04,380 --> 00:28:09,120 your questions and in that case that's 727 00:28:06,900 --> 00:28:10,980 probably going to be a better choice 728 00:28:09,120 --> 00:28:12,480 I think we have time for just one more 729 00:28:10,980 --> 00:28:14,880 quick one 730 00:28:12,480 --> 00:28:18,179 this one part of me I'm not doing my job 731 00:28:14,880 --> 00:28:20,760 properly it's fine 732 00:28:18,179 --> 00:28:23,700 I just uh it's a continuation of my 733 00:28:20,760 --> 00:28:26,100 previous question uh so you said uh it 734 00:28:23,700 --> 00:28:28,260 was capitalizing and I kept looking for 735 00:28:26,100 --> 00:28:30,779 capitalizing on there and I didn't see 736 00:28:28,260 --> 00:28:33,240 it but it would ID did sees that class 737 00:28:30,779 --> 00:28:36,539 HTTP headers inherits from case and 738 00:28:33,240 --> 00:28:38,520 sensitive mapping so I'm assuming in a 739 00:28:36,539 --> 00:28:41,940 in a in a second there is where it 740 00:28:38,520 --> 00:28:43,620 normalizes and yeah okay you see how the 741 00:28:41,940 --> 00:28:46,320 there's a inheritance from case 742 00:28:43,620 --> 00:28:48,179 insensitive mapping so I'm assuming HTTP 743 00:28:46,320 --> 00:28:51,179 headers is addiction is a special 744 00:28:48,179 --> 00:28:53,820 dictionary yes sorry regular lookups are 745 00:28:51,179 --> 00:28:57,360 case insensitive that so it doesn't 746 00:28:53,820 --> 00:28:59,039 matter uh what Casey is there it is 747 00:28:57,360 --> 00:29:00,659 that's in the slide I just didn't say it 748 00:28:59,039 --> 00:29:03,900 this time yes I think that I think 749 00:29:00,659 --> 00:29:06,419 that's Sasha action actual answer right 750 00:29:03,900 --> 00:29:07,919 so it normalizes the headers as it's 751 00:29:06,419 --> 00:29:09,840 parsing them and then gives you a case 752 00:29:07,919 --> 00:29:12,900 insensitive lookup when you ask for them 753 00:29:09,840 --> 00:29:15,059 again taking away that tedium 754 00:29:12,900 --> 00:29:18,480 protecting you from the tedious stuff 755 00:29:15,059 --> 00:29:19,690 okay is that all can we give um one more 756 00:29:18,480 --> 00:29:21,960 round of applause to Curtis 757 00:29:19,690 --> 00:29:22,860 [Applause] 758 00:29:21,960 --> 00:29:26,830 foreign 759 00:29:22,860 --> 00:29:26,830 [Applause]