The x-forwarded-for example is the perfect example to explain why you should just escape anything and never try to guess trust boundaries. Sure. When you started with that query, that IP address likely was just REMOTE_ADDR (guaranteed to not contain "bad" characters), but then the app was put behind a reverse proxy and support for x-forwarded-for was added, suddenly changing the IP address to something user-modifyabl…
It's not a standard header, it's just a header... a string.
IP addresses may easily be IPv6.
You can easily have comma delimited lists of them.
You don't know how long the input will be.
And unless you are sure that your network is cleaning the incoming requests and setting those headers, you shouldn't even begin to think that they are to be trusted for anything.